1"""DotView.py -- A one-window app demonstrating how to write a custom NSView.
2
3To build the demo program, run this line in Terminal.app:
4
5    $ python setup.py py2app -A
6
7This creates a directory "dist" containing DotView.app. (The
8-A option causes the files to be symlinked to the .app bundle instead
9of copied. This means you don't have to rebuild the app if you edit the
10sources or nibs.)
11"""
12
13# Created by Etienne Posthumus on Thu Dec 26 2002, after Apple's
14# ObjC DotView example.
15# Edited and enhanced by JvR, 2003.
16#
17# The main difference with the Apple DotView demo is that our custom view
18# is embedded in a scroll view. It turns out that this is almost no work
19# in InterfaceBuilder (select the view, then go to Layout -> Make subvies of
20# -> Scroll View), and *no* work in the code. It was too easy, so for kicks
21# I added zoom functionality and a "Show rulers" checkbox.
22
23from Cocoa import *
24from PyObjCTools import AppHelper
25
26ZOOM = 2.0
27
28
29# class defined in MainMenu.nib
30class DotView(NSView):
31    colorWell = objc.IBOutlet()
32    sizeSlider = objc.IBOutlet()
33
34    def initWithFrame_(self, frame):
35        self.center = (50.0, 50.0)
36        super(DotView, self).initWithFrame_(frame)
37        self.radius = 10.0
38        self.color = NSColor.redColor()
39        return self
40
41    def awakeFromNib(self):
42        self.colorWell.setColor_(self.color)
43        self.sizeSlider.setFloatValue_(self.radius)
44        scrollView = self.superview().superview()
45        scrollView.setHasHorizontalRuler_(1)
46        scrollView.setHasVerticalRuler_(1)
47
48    @objc.IBAction
49    def zoomIn_(self, sender):
50        (x, y), (bw, bh) = self.bounds()
51        (x, y), (fw, fh) = self.frame()
52        self.setBoundsSize_((bw / ZOOM, bh / ZOOM))
53        self.setFrameSize_((fw * ZOOM, fh * ZOOM))
54        self.setNeedsDisplay_(True)
55
56    @objc.IBAction
57    def zoomOut_(self, sender):
58        (x, y), (bw, bh) = self.bounds()
59        (x, y), (fw, fh) = self.frame()
60        self.setBoundsSize_((bw * ZOOM, bh * ZOOM))
61        self.setFrameSize_((fw / ZOOM, fh / ZOOM))
62        self.setNeedsDisplay_(True)
63
64    @objc.IBAction
65    def setRulersVisible_(self, button):
66        scrollView = self.superview().superview()
67        scrollView.setRulersVisible_(button.state())
68
69    def isOpaque(self):
70        return True
71
72    def mouseDown_(self, event):
73        eventLocation = event.locationInWindow()
74        if event.modifierFlags() & NSCommandKeyMask:
75            clipView = self.superview()
76            self.originalPoint = eventLocation
77            self.originalOffset = clipView.bounds()[0]
78        else:
79            self.center = self.convertPoint_fromView_(eventLocation, None)
80            self.setNeedsDisplay_(True)
81            self.autoscroll_(event)
82
83    def mouseDragged_(self, event):
84        if event.modifierFlags() & NSCommandKeyMask:
85            clipView = self.superview()
86            eventLocation = event.locationInWindow()
87            ox, oy = self.originalPoint
88            x, y = eventLocation
89            dx, dy = x - ox, y - oy
90            x, y = self.originalOffset
91            ox, oy = clipView.constrainScrollPoint_((x - dx, y - dy))
92            clipView.scrollToPoint_((ox, oy))
93            clipView.superview().reflectScrolledClipView_(clipView)
94        else:
95            self.mouseDown_(event)
96
97    def drawRect_(self, rect):
98        NSColor.whiteColor().set()
99        NSRectFill(self.bounds())
100        origin = (self.center[0]-self.radius, self.center[1]-self.radius)
101        size = (2 * self.radius, 2 * self.radius)
102        dotRect = (origin, size)
103        self.color.set()
104        NSBezierPath.bezierPathWithOvalInRect_(dotRect).fill()
105
106    @objc.IBAction
107    def setRadius_(self, sender):
108        self.radius = sender.floatValue()
109        self.setNeedsDisplay_(True)
110
111    @objc.IBAction
112    def setColor_(self, sender):
113        self.color = sender.color()
114        self.setNeedsDisplay_(True)
115
116
117if __name__ == "__main__":
118    AppHelper.runEventLoop()
119