from Cocoa import *
from Quartz import *
import objc
from Extras import makeRandomPointInRect
from Circle import Circle
gCircleCount = 3
class NSEvent (objc.Category(NSEvent)):
def locationInView_(self, view):
return view.convertPoint_fromView_(self.locationInWindow(), None)
class TLayerView (NSView):
circles = objc.ivar()
shadowRadius = objc.ivar(type=objc._C_FLT)
shadowOffset = objc.ivar(type=CGSize.__typestr__)
useTLayer = objc.ivar(type=objc._C_BOOL)
def initWithFrame_(self, frame):
circleRadius = 100
colors = [
( 0.5, 0.0, 0.5, 1 ),
( 1.0, 0.7, 0.0, 1 ),
( 0.0, 0.5, 0.0, 1 ),
]
self = super(TLayerView, self).initWithFrame_(frame)
if self is None:
return None
self.useTLayer = False;
self.circles = []
for c in colors:
color = NSColor.colorWithCalibratedRed_green_blue_alpha_(*c)
circle = Circle.alloc().init()
circle.color = color
circle.radius = circleRadius
circle.center = makeRandomPointInRect(self.bounds())
self.circles.append(circle)
self.registerForDraggedTypes_([NSColorPboardType])
self.setNeedsDisplay_(True)
return self
def setShadowRadius_(self, radius):
if radius != self.shadowRadius:
self.shadowRadius = radius
self.setNeedsDisplay_(True)
def setShadowOffset_(self, offset):
if self.shadowOffset != offset:
self.shadowOffset = offset
self.setNeedsDisplay_(True)
def setUsesTransparencyLayers_(self, state):
if self.useTLayer != state:
self.useTLayer = state
self.setNeedsDisplay_(True)
def isOpaque(self):
return True
def acceptsFirstMouse_(self, event):
return True
def boundsForCircle_(self, circle):
dx = 2 * abs(self.shadowOffset.width) + 2 * self.shadowRadius;
dy = 2 * abs(self.shadowOffset.height) + 2 * self.shadowRadius;
return NSInsetRect(circle.bounds(), -dx, -dy)
def dragCircleAtIndex_withEvent_(self, index, event):
circle = self.circles[index]
del self.circles[index]
self.circles.append(circle)
self.setNeedsDisplayInRect_(self.boundsForCircle_(circle))
mask = NSLeftMouseDraggedMask | NSLeftMouseUpMask;
start = event.locationInView_(self)
while (1):
event = self.window().nextEventMatchingMask_(mask)
if event.type() == NSLeftMouseUp:
break
self.setNeedsDisplayInRect_(self.boundsForCircle_(circle))
center = circle.center
point = event.locationInView_(self)
center.x += point.x - start.x;
center.y += point.y - start.y;
circle.center = center
self.setNeedsDisplayInRect_(self.boundsForCircle_(circle))
start = point;
def indexOfCircleAtPoint_(self, point):
for idx, circle in reversed(list(enumerate(self.circles))):
center = circle.center
radius = circle.radius
dx = point.x - center.x
dy = point.y - center.y
if dx * dx + dy * dy < radius * radius:
return idx
return -1
def mouseDown_(self, event):
point = event.locationInView_(self)
index = self.indexOfCircleAtPoint_(point)
if index >= 0:
self.dragCircleAtIndex_withEvent_(index, event)
def setFrame_(self, frame):
super(TLayerView, self).setFrame_(frame)
self.setNeedsDisplay_(True)
def drawRect_(self, rect):
context = NSGraphicsContext.currentContext().graphicsPort()
CGContextSetRGBFillColor(context, 0.7, 0.7, 0.9, 1)
CGContextFillRect(context, rect)
CGContextSetShadow(context, self.shadowOffset, self.shadowRadius)
if self.useTLayer:
CGContextBeginTransparencyLayer(context, None)
for circle in self.circles:
bounds = self.boundsForCircle_(circle)
if NSIntersectsRect(bounds, rect):
circle.draw()
if self.useTLayer:
CGContextEndTransparencyLayer(context)
def draggingEntered_(self, sender):
# Since we have only registered for NSColorPboardType drags, this is
# actually unneeded. If you were to register for any other drag types,
# though, this code would be necessary.
if (sender.draggingSourceOperationMask() & NSDragOperationGeneric) != 0:
pasteboard = sender.draggingPasteboard()
if pasteboard.types().containsObject_(NSColorPboardType):
return NSDragOperationGeneric
return NSDragOperationNone
def performDragOperation_(self, sender):
point = self.convertPoint_fromView_(sender.draggingLocation(), None)
index = self.indexOfCircleAtPoint_(point)
if index >= 0:
# The current drag location is inside the bounds of a circle so we
# accept the drop and move on to concludeDragOperation:.
return True
return False
def concludeDragOperation_(self, sender):
color = NSColor.colorFromPasteboard_(sender.draggingPasteboard())
point = self.convertPoint_fromView_(sender.draggingLocation(), None)
index = self.indexOfCircleAtPoint_(point)
if index >= 0:
circle = self.circles[index]
circle.color = color
self.setNeedsDisplayInRect_(self.boundsForCircle_(circle))
|