Grady¶
A PyObjC Example without documentation
Sources¶
AppDelegate.py¶
import Cocoa
import objc
from MyWindowController import MyWindowController
class AppDelegate(Cocoa.NSObject):
myWindowController = objc.ivar()
@objc.IBAction
def newDocument_(self, sender):
if self.myWindowController is None:
self.myWindowController = MyWindowController.alloc().initWithWindowNibName_(
"TestWindow"
)
self.myWindowController.showWindow_(self)
def applicationDidFinishLaunching_(self, notification):
self.newDocument_(self)
def validateMenuItem_(self, theMenuItem):
enable = self.respondsToSelector_(theMenuItem.action())
# disable "New" if the window is already up
if theMenuItem.action() == b"newDocument:":
if self.myWindowController.window().isKeyWindow():
enable = False
return enable
MyBaseGradientView.py¶
import Cocoa
import objc
class MyBaseGradientView(Cocoa.NSView):
myGradient = objc.ivar()
myStartColor = objc.ivar()
myEndColor = objc.ivar()
forceColorChange = objc.ivar.bool()
myAngle = objc.ivar.double()
myIsRadial = objc.ivar.bool()
myOffsetPt = objc.ivar.NSPoint()
def resetGradient(self):
if self.forceColorChange and self.myGradient is not None:
self.myGradient = None
if self.myGradient is None:
self.myGradient = (
Cocoa.NSGradient.alloc().initWithStartingColor_endingColor_(
self.myStartColor, self.myEndColor
)
)
self.forceColorChange = False
def setStartColor_(self, startColor):
self.myStartColor = startColor
self.forceColorChange = True
self.setNeedsDisplay_(True)
def setEndColor_(self, endColor):
self.myEndColor = endColor
self.forceColorChange = True
self.setNeedsDisplay_(True)
def setAngle_(self, angle):
self.myAngle = angle
self.setNeedsDisplay_(True)
def setRadialDraw_(self, isRadial):
self.myIsRadial = isRadial
self.setNeedsDisplay_(True)
def getRelativeCenterPositionFromEvent_(self, theEvent):
curMousePt = self.convertPoint_fromView_(theEvent.locationInWindow(), None)
pt = Cocoa.NSMakePoint(
(curMousePt.x - Cocoa.NSMidX(self.bounds()))
/ (self.bounds().size.width / 2.0),
(curMousePt.y - Cocoa.NSMidY(self.bounds()))
/ (self.bounds().size.height / 2.0),
)
return pt
def mouseDown_(self, theEvent):
if self.myIsRadial:
self.myOffsetPt = self.getRelativeCenterPositionFromEvent_(theEvent)
self.setNeedsDisplay_(True)
def mouseDragged_(self, theEvent):
if self.myIsRadial:
self.myOffsetPt = self.getRelativeCenterPositionFromEvent_(theEvent)
self.setNeedsDisplay_(True)
MyBezierGradientView.py¶
import Cocoa
from MyBaseGradientView import MyBaseGradientView
class MyBezierGradientView(MyBaseGradientView):
def init(self):
self = super(MyBaseGradientView, self).init()
if self is None:
return None
self.myOffsetPt = Cocoa.NSMakePoint(0.0, 0.0)
return self
def drawRect_(self, rect):
self.resetGradient()
bezierPath = Cocoa.NSBezierPath.alloc().init()
bezierPath.appendBezierPathWithOvalInRect_(rect)
if self.myIsRadial:
self.myGradient.drawInBezierPath_relativeCenterPosition_(
bezierPath, self.myOffsetPt
)
else:
self.myGradient.drawInBezierPath_angle_(bezierPath, self.myAngle)
MyRectGradientView.py¶
import Cocoa
from MyBaseGradientView import MyBaseGradientView
class MyRectGradientView(MyBaseGradientView):
def init(self):
self = super().init()
if self is None:
return self
self.myOffsetPt = Cocoa.NSMakePoint(0.0, 0.0)
return self
def drawRect_(self, rect):
self.resetGradient()
# if the "Radial Gradient" checkbox is turned on, draw using 'myOffsetPt'
if self.myIsRadial:
self.myGradient.drawInRect_relativeCenterPosition_(
self.bounds(), self.myOffsetPt
)
else:
self.myGradient.drawInRect_angle_(self.bounds(), self.myAngle)
MyWindowController.py¶
import Cocoa
import objc
from objc import super # noqa: A004
class MyWindowController(Cocoa.NSWindowController):
rectGradientView = objc.IBOutlet()
bezierGradientView = objc.IBOutlet()
startColorWell = objc.IBOutlet()
endColorWell = objc.IBOutlet()
angle = objc.IBOutlet()
angleSlider = objc.IBOutlet()
radialCheck = objc.IBOutlet()
radialExplainText = objc.IBOutlet()
def initWithPath_(self, newPath):
return super().initWithWindowNibName_("TestWindow")
def awakeFromNib(self):
# make sure our angle text input keep the right format
formatter = Cocoa.NSNumberFormatter.alloc().init()
formatter.setNumberStyle_(Cocoa.NSNumberFormatterDecimalStyle)
self.angle.cell().setFormatter_(formatter)
# setup the initial start color
self.rectGradientView.setStartColor_(Cocoa.NSColor.orangeColor())
self.bezierGradientView.setStartColor_(Cocoa.NSColor.orangeColor())
self.startColorWell.setColor_(Cocoa.NSColor.orangeColor())
# setup the initial end color
self.rectGradientView.setEndColor_(Cocoa.NSColor.blueColor())
self.bezierGradientView.setEndColor_(Cocoa.NSColor.blueColor())
self.endColorWell.setColor_(Cocoa.NSColor.blueColor())
# setup the initial angle value
self.rectGradientView.setAngle_(90.0)
self.bezierGradientView.setAngle_(90.0)
self.angle.setStringValue_("90.0")
self.angleSlider.setFloatValue_(90.0)
@objc.IBAction
def swapColors_(self, sender):
startColor = self.startColorWell.color()
endColor = self.endColorWell.color()
# change all our view's start and end colors
self.rectGradientView.setStartColor_(endColor)
self.rectGradientView.setEndColor_(startColor)
self.bezierGradientView.setStartColor_(endColor)
self.bezierGradientView.setEndColor_(startColor)
# fix our color wells
self.startColorWell.setColor_(endColor)
self.endColorWell.setColor_(startColor)
@objc.IBAction
def startColor_(self, sender):
newColor = sender.color()
self.rectGradientView.setStartColor_(newColor)
self.bezierGradientView.setStartColor_(newColor)
@objc.IBAction
def endColor_(self, sender):
newColor = sender.color()
self.rectGradientView.setEndColor_(newColor)
self.bezierGradientView.setEndColor_(newColor)
def controlTextDidEndEditing_(self, notification):
theAngle = self.angle.floatValue()
self.rectGradientView.setAngle_(theAngle)
self.bezierGradientView.setAngle_(theAngle)
theAngleDougle = self.angle.doubleValue()
self.angleSlider.setDoubleValue_(theAngleDougle)
self.angleSlider.setNeedsDisplay_(True)
@objc.IBAction
def angleSliderChange_(self, sender):
angleValue = sender.floatValue()
self.rectGradientView.setAngle_(angleValue)
self.bezierGradientView.setAngle_(angleValue)
self.angle.setDoubleValue_(angleValue)
@objc.IBAction
def radialDraw_(self, sender):
self.rectGradientView.setRadialDraw_(sender.selectedCell().state())
self.bezierGradientView.setRadialDraw_(sender.selectedCell().state())
# angle factor does not relate to radial draws
self.angleSlider.setEnabled_(not sender.selectedCell().state())
self.angle.setEnabled_(not sender.selectedCell().state())
# hide/show the explain text for radial gradients
self.radialExplainText.setHidden_(not sender.selectedCell().state())
main.py¶
import AppDelegate # noqa: F401
import MyBaseGradientView # noqa: F401
import MyBezierGradientView # noqa: F401
import MyRectGradientView # noqa: F401
import MyWindowController # noqa: F401
from PyObjCTools import AppHelper
AppHelper.runEventLoop()
setup.py¶
"""
Script for building the example.
Usage:
python3 setup.py py2app
"""
from setuptools import setup
setup(
name="Grady",
app=["main.py"],
data_files=["English.lproj"],
setup_requires=["py2app", "pyobjc-framework-Cocoa"],
)