from Quartz import *

import Utilities


def scaleShadowOffset(offset):
    shadowScaling = Utilities.getScalingFactor()
    # Adjust the shadow offset if scaling to export as bits. This is 
    # equivalent to scaling base space by the scaling factor.
    if shadowScaling != 1.0:
        offset = CGSizeApplyAffineTransform(offset, 
                    CGAffineTransformMakeScale(shadowScaling, shadowScaling))
    return offset


def createTrianglePath(context):
    CGContextBeginPath(context)
    CGContextMoveToPoint(context, 0, 0)
    CGContextAddLineToPoint(context, 50, 0)
    CGContextAddLineToPoint(context, 25, 50)
    CGContextClosePath(context)

def drawSimpleShadow(context):
    r = CGRectMake(20, 20, 100, 200)
    
    CGContextTranslateCTM(context, 20, 300)
    
    # A blur of 0 is a hard edge blur.
    blur = 0
    # An offset where both components are negative casts a shadow to the
    # left and down from the object. The coordinate system for the offset
    # is base space, not current user space.
    offset = CGSize(-7, -7)
    offset = scaleShadowOffset(offset)

    # Set the shadow in the context. 
    CGContextSetShadow(context, offset, blur)
    
    # Object 1. 
    # Paint a rectangle.
    CGContextFillRect(context, r)

    # Object 2.
    CGContextTranslateCTM(context, 150, 0)
    # A blur of 3 is a soft blur more
    # appropriate for a shadow effect.
    blur = 3
    CGContextSetShadow(context, offset, blur)

    # Fill an ellipse to the right of the rect.
    CGContextBeginPath(context)
    Utilities.myCGContextAddEllipseInRect(context, r)
    CGContextFillPath(context)

    # Object 3.
    CGContextTranslateCTM(context, -130, -140)
    # Scale the coordinate system but the shadow is not affected. The offset
    # is in the base space of the context. Typically it looks best if the shapes
    # have a uniform shadow regardless of how the shapes were created, scaled,
    # rotated, or otherwise transformed.
    CGContextScaleCTM(context, 2, 2)
    createTrianglePath(context)
    CGContextSetStrokeColorWithColor(context, Utilities.getRGBOpaqueRedColor())
    
    CGContextSetLineWidth(context, 5)
    # Stroking produces a shadow as well.
    CGContextStrokePath(context)
    
    # Object 4.
    CGContextTranslateCTM(context, 75, 0)
    createTrianglePath(context)
    # Cast the shadow to the left and up from
    # the shape painted.
    offset.width = -5
    offset.height = +7
    offset = scaleShadowOffset(offset)
    
    # The shadow can be colored. Create a CGColorRef
    # that represents a red color with opacity of 0.3333...
    shadowColor = CGColorCreateCopyWithAlpha(Utilities.getRGBOpaqueRedColor(), 1.0/3.0)
    
    CGContextSetShadowWithColor(context, offset, blur, shadowColor)
    CGContextStrokePath(context)

    # Object 5. Three stroked circles.
    CGContextTranslateCTM(context, -75, -65)
    # Set a black shadow offset at -7,-7.
    offset.width = -7
    offset.height = -7

    offset = scaleShadowOffset(offset)

    CGContextSetShadow(context, offset, blur)
    # Draw a set of three circles side by side.
    CGContextBeginPath(context)
    CGContextSetLineWidth(context, 3)
    r = CGRectMake(30, 20, 20, 20)
    Utilities.myCGContextAddEllipseInRect(context, r)
    r = CGRectOffset(r, 20, 0)
    Utilities.myCGContextAddEllipseInRect(context, r)
    r = CGRectOffset(r, 20, 0)
    Utilities.myCGContextAddEllipseInRect(context, r)
    CGContextStrokePath(context)


def doShadowScaling(context):
    offset = CGSize(-7, -7)
    blur = 3

    CGContextTranslateCTM(context, 20, 220)
    CGContextSetShadow(context, scaleShadowOffset(offset), blur)
    
    # Object 1
    # Draw a triangle filled with black and shadowed with black.
    createTrianglePath(context)
    CGContextFillPath(context)
    
    # Object 2
    # Scaling without changing the shadow doesn't impact
    # the shadow offset or blur.
    t = CGAffineTransformMakeScale(2, 2)
    CGContextConcatCTM(context, t)
    CGContextTranslateCTM(context, 40, 0)
    createTrianglePath(context)
    CGContextFillPath(context)
    
    # Object 3
    # By transforming the offset you can transform the shadow. 
    # This may be desirable if you are drawing a zoomed view.
    offset = CGSizeApplyAffineTransform(offset, t)
    CGContextSetShadow(context, scaleShadowOffset(offset), blur)
    CGContextTranslateCTM(context, 70, 0)
    createTrianglePath(context)
    CGContextFillPath(context)


def drawFillAndStrokeWithShadow(context):
    r = CGRectMake(60, 60, 100, 100)
    offset = CGSize(-7, -7)
    blur = 3

    # Set the shadow.
    CGContextSetShadow(context, scaleShadowOffset(offset), blur)
    
    CGContextSetFillColorWithColor(context, Utilities.getRGBOpaqueOrangeColor())

    # Draw the graphic on the left.
    CGContextBeginPath(context)
    Utilities.myCGContextAddEllipseInRect(context, r)
    CGContextDrawPath(context, kCGPathFillStroke)
    
    # Draw the graphic on the right.
    r = CGRectOffset(r, 125, 0)
    # Begin the transparency layer.
    CGContextBeginTransparencyLayer(context, None)
    if 1:
        Utilities.myCGContextAddEllipseInRect(context, r)
        CGContextDrawPath(context, kCGPathFillStroke)
    # End the transparency layer.
    CGContextEndTransparencyLayer(context)

def drawColoredLogo(context):
	r = CGRectMake(0, 0, 100, 100)
	CGContextSaveGState(context)
        if 1:
		# Position the center of the rectangle on the left.
		CGContextTranslateCTM(context, 140, 140)
		# Rotate so that the rectangles are rotated 45 degrees 
		# about the current coordinate origin.
		CGContextRotateCTM(context, Utilities.DEGREES_TO_RADIANS(45))
		# Translate so that the center of the rect is at the previous origin.
		CGContextTranslateCTM(context, 
                        -r.size.width/2, -r.size.height/2)
		# Set the fill color to a purple color.
		CGContextSetFillColorWithColor(context, 
                        Utilities.getRGBOpaquePurpleColor())
		# Fill the first rectangle.
		CGContextFillRect(context, r)
		# Position to draw the right-most rectangle.
		CGContextTranslateCTM(context, 60, -60)
		# Set the fill color to a yellow color.
		CGContextSetFillColorWithColor(context, 
                        Utilities.getRGBOpaqueYellowColor())
		CGContextFillRect(context, r)
		
		# Position for the center rectangle.
		CGContextTranslateCTM(context, -30, +30)
		# Set the stroke color to an orange color.
		CGContextSetStrokeColorWithColor(context, 
                        Utilities.getRGBOpaqueOrangeColor())
		# Stroke the rectangle with a linewidth of 12.
		CGContextStrokeRectWithWidth(context, r, 12)
	CGContextRestoreGState(context)

def showComplexShadowIssues(context):
    offset = CGSize(-6, -6)
    blur = 3

    # Set the shadow.
    CGContextSetShadow(context, scaleShadowOffset(offset), blur)
    # Draw the colored logo.
    drawColoredLogo(context)

def showComplexShadow(context):
    offset = CGSize(-6, -6)
    blur = 3
    
    # Set the shadow.
    CGContextSetShadow(context, scaleShadowOffset(offset), blur)

    # Begin a transparency layer. A snapshot is made of the graphics state and 
    # the shadow parameter is temporarily reset to no shadow, the blend mode 
    # is set to Normal, and the global alpha parameter is set to 1.0.
    #
    # All drawing that occurs after CGContextBeginTransparencyLayer but before 
    # CGContextEndTransparencyLayer is collected together and when 
    # CGContextEndTransparencyLayer is called, Quartz composites the collected 
    # drawing to the context, using the global alpha, blend mode, and shadow 
    # that was in effect when CGContextBeginTransparencyLayer was called.

    CGContextBeginTransparencyLayer(context, None)
    # Draw the colored logo.
    drawColoredLogo(context)

    # Ending the transparency layer causes all drawing in the transparency 
    # layer to be composited with the global alpha, blend mode, and shadow 
    # in effect at the time CGContextBeginTransparencyLayer was called.  The 
    # graphics state is restored to that in effect when 
    # CGContextBeginTransparencyLayer was called.    

    # This restores the graphics state to that in effect
    # at the last call to CGContextBeginTransparencyLayer. 
    CGContextEndTransparencyLayer(context)

def doLayerCompositing(context):
    r = CGRectMake(40, 50, 142, 180)
    # Object 1.
    CGContextTranslateCTM(context, 20, 20)
    CGContextSetFillColorWithColor(context, Utilities.getRGBOpaqueGreenColor())
    # Draw a green background.
    CGContextFillRect(context, r)
    # Draw the colored logo.
    drawColoredLogo(context)

    # Object 2.
    CGContextTranslateCTM(context, 300, 0)
    CGContextSetFillColorWithColor(context, Utilities.getRGBOpaqueGreenColor())
    # Draw a green background.
    CGContextFillRect(context, r)
    
    # Draw the rectangles with opacity 0.75.
    CGContextSetAlpha(context, 0.75)
    
    drawColoredLogo(context)

    # Object 3.
    CGContextTranslateCTM(context, 300, 0)
    # Set the alpha to 1.0 for drawing the background.
    CGContextSetAlpha(context, 1.0)
    CGContextSetFillColorWithColor(context, Utilities.getRGBOpaqueGreenColor())
    CGContextFillRect(context, r)
    # Draw the rectangles with opacity 0.75.
    CGContextSetAlpha(context, 0.75)
    # Begin a transparency layer. Drawing collected in
    # this transparency layer will be composited with an
    # alpha value of 0.75 when the transparency layer is ended.
    CGContextBeginTransparencyLayer(context, None)
    if 1:
        # Draw the colored logo into the transparency layer.
        drawColoredLogo(context)

    # Ending the transparency layer causes the drawing
    # to then be composited with the global alpha value
    # in effect when CGContextBeginTransparencyLayer was called.
    CGContextEndTransparencyLayer(context)

def shadowPDFDocument(context, url):
    pdfDoc = CGPDFDocumentCreateWithURL(url)
    offset = CGSize(-7, -7)
    
    if pdfDoc is None:
        print >>sys.stderr, "Couldn't create PDF document reference!"
        return
	
    r = CGPDFDocumentGetMediaBox(pdfDoc, 1)
    r.origin.x = 20
    r.origin.y = 20

    # Set the shadow.
    CGContextSetShadow(context, scaleShadowOffset(offset), 3)
    
    # On Tiger and later, there is no need to use
    # a transparency layer to draw a PDF document as
    # a grouped object. On Panther, you can do so
    # by using a transparency layer. Drawing collected in
    # this transparency layer is drawn with the shadow
    # when the layer is ended.
    CGContextBeginTransparencyLayer(context, None)
    if 1:
        CGContextDrawPDFDocument(context, r, pdfDoc, 1)

    CGContextEndTransparencyLayer(context)
