""" Example for using CGShading and CGFunction. This code is directly translated from procedural C code and is definitely not good Python style. """ from PyObjCTools import NibClassBuilder from Quartz import * import math import random import objc import array NibClassBuilder.extractClasses("MainMenu") # Global variables frequency = [ 0.0, 0.0, 0.0, 0.0 ] startPoint = CGPoint(0.0, 0.0) startRadius = 0.0 startExtend = False endPoint = CGPoint(0.0, 0.0) endRadius = 0.0 endExtend = False shading = None function = None getFunction = None getShading = None colorspace = None DEFAULT_WIDTH = 256 DEFAULT_HEIGHT = 256 MAX_WIDTH = 1000 MAX_HEIGHT = 1000 def randomPoint(): return CGPoint(random.random(), random.random()) def evaluate1(components, input, output): out = [] for k in range(components-1): out.append(1 + (math.sin(input[0] * frequency[k]))/2); out.append(1) return out def getFunction1(colorspace): callbacks = ( evaluate1, None ) domain = array.array('f', [ -2 * math.pi, 2 * math.pi ]) range = array.array('f', [ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 ]) components = 1 + CGColorSpaceGetNumberOfComponents(colorspace) return CGFunctionCreate(components, 1, domain, components, range, callbacks) def evaluate2(components, input, output): c = [ 0.510, 0.188, 0.910, 0.122 ] v = input[0] out = [] for k in range(components-1): if v < 0.5: out.append(c[k] * 2 * (0.5 - v)) else: out.append(c[k] * 2 * (v - 0.5)) out.append(1) return out def getFunction2(colorspace): callbacks = ( evaluate2, None ) domain = [0, 1] range = [ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 ] components = 1 + CGColorSpaceGetNumberOfComponents(colorspace); return CGFunctionCreate(components, 1, domain, components, range, callbacks) def evaluate3(components, input, output): c = [ 0.3, 0, 0, 0 ] out = [] for k in range(components-1): out.append(c[k] * input[0]) out.append(1) return out def getFunction3(colorspace): callbacks = ( evaluate3, None ) domain = [0, 1] range = [ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 ] components = 1 + CGColorSpaceGetNumberOfComponents(colorspace); return CGFunctionCreate(components, 1, domain, components, range, callbacks); def getAxialShading(colorspace, function): return CGShadingCreateAxial(colorspace, startPoint, endPoint, function, startExtend, endExtend); def getRadialShading(colorspace, function): return CGShadingCreateRadial(colorspace, startPoint, startRadius, endPoint, endRadius, function, startExtend, endExtend); class MyQuartzView (NibClassBuilder.AutoBaseClass): def initWithFrame_(self, frameRect): global startPoint, startRadius, startExtend global endPoint, endRadius, endExtend super(MyQuartzView, self).initWithFrame_(frameRect) startPoint = CGPoint(0, 0) startRadius = 0; startExtend = False; endPoint = CGPointMake( 0, 0 ); endRadius = 0; endExtend = False; return self; def drawRect_(self, rect): currentContext = NSGraphicsContext.currentContext().graphicsPort() # Note that at this point the current context CTM is set up such # that the context size corresponds to the size of the view # i.e. one unit in the context == one pixel # Also, the origin is in the bottom left of the view with +y pointing up global getFunction bounds = self.bounds() angle = 0; sx = sy = 1; width = bounds.size.width; height = bounds.size.height; if getFunction is None: self.randomize_(self) m = CGAffineTransformIdentity; m = CGAffineTransformRotate(m, angle); m = CGAffineTransformScale(m, width, height); m = CGAffineTransformScale(m, sx, sy); CGContextBeginPage(currentContext, bounds) CGContextTranslateCTM(currentContext, bounds.size.width/2, bounds.size.height/2); CGContextConcatCTM(currentContext, m); CGContextTranslateCTM(currentContext, -0.5, -0.5); CGContextSaveGState(currentContext); CGContextClipToRect(currentContext, CGRectMake(0, 0, 1, 1)); CGContextSetRGBFillColor(currentContext, 0.7, 0.7, 0.9, 1); CGContextFillRect(currentContext, CGRectMake(0, 0, 1, 1)); CGContextDrawShading(currentContext, shading); CGContextRestoreGState(currentContext); CGContextSaveGState(currentContext); CGContextClipToRect(currentContext, CGRectMake(0, 0, 1, 1)); CGContextSetRGBStrokeColor(currentContext, 1, 0, 0, 1); if (getShading == getRadialShading): CGContextAddArc(currentContext, startPoint.x, startPoint.y, startRadius, math.radians(0), math.radians(360), True) CGContextClosePath(currentContext) CGContextMoveToPoint(currentContext, endPoint.x + endRadius, endPoint.y) CGContextAddArc(currentContext, endPoint.x, endPoint.y, endRadius, math.radians(0), math.radians(360), True) CGContextClosePath(currentContext) CGContextMoveToPoint(currentContext, startPoint.x + 0.01, startPoint.y) CGContextAddArc(currentContext, startPoint.x, startPoint.y, 0.01, math.radians(0), math.radians(360), True) CGContextClosePath(currentContext) CGContextMoveToPoint(currentContext, startPoint.x, startPoint.y) CGContextAddLineToPoint(currentContext, endPoint.x, endPoint.y) ctm = CGContextGetCTM(currentContext) CGContextConcatCTM(currentContext, CGAffineTransformInvert(ctm)) CGContextStrokePath(currentContext) CGContextRestoreGState(currentContext) CGContextSaveGState(currentContext) CGContextSetGrayStrokeColor(currentContext, 0, 1) CGContextAddRect(currentContext, CGRectMake(0, 0, 1, 1)) ctm = CGContextGetCTM(currentContext) CGContextConcatCTM(currentContext, CGAffineTransformInvert(ctm)) CGContextStrokePath(currentContext) CGContextRestoreGState(currentContext) CGContextEndPage(currentContext) CGContextFlush(currentContext); def randomize_(self, sender): global colorspace, getFunction, getShading global function, shading global startPoint, startRadius, endPoint, endRadius if colorspace is None: colorspace = CGColorSpaceCreateDeviceRGB() for k in range(len(frequency)): frequency[k] = random.random() startPoint = randomPoint(); startRadius = random.random() / 2; endPoint = randomPoint(); endRadius = random.random() / 2; if getFunction == getFunction1: getFunction = getFunction2 elif getFunction == getFunction2: getFunction = getFunction3 else: getFunction = getFunction1 if getShading == getAxialShading: getShading = getRadialShading else: getShading = getAxialShading function = getFunction(colorspace) shading = getShading(colorspace, function) self.setNeedsDisplay_(True) def toggleStartExtend_(self, sender): global startExtend, shading startExtend = not startExtend shading = getShading(colorspace, function) self.setNeedsDisplay_(True) def toggleEndExtend_(self, sender): global endExtend, shading endExtend = not endExtend shading = getShading(colorspace, function) self.setNeedsDisplay_(True)