~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to wxPython/samples/doodle/doodle.py

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# doodle.py
 
2
 
 
3
"""
 
4
This module contains the DoodleWindow class which is a window that you
 
5
can do simple drawings upon.
 
6
"""
 
7
 
 
8
 
 
9
import wx                  # This module uses the new wx namespace
 
10
 
 
11
#----------------------------------------------------------------------
 
12
 
 
13
class DoodleWindow(wx.Window):
 
14
    menuColours = { 100 : 'Black',
 
15
                    101 : 'Yellow',
 
16
                    102 : 'Red',
 
17
                    103 : 'Green',
 
18
                    104 : 'Blue',
 
19
                    105 : 'Purple',
 
20
                    106 : 'Brown',
 
21
                    107 : 'Aquamarine',
 
22
                    108 : 'Forest Green',
 
23
                    109 : 'Light Blue',
 
24
                    110 : 'Goldenrod',
 
25
                    111 : 'Cyan',
 
26
                    112 : 'Orange',
 
27
                    113 : 'Navy',
 
28
                    114 : 'Dark Grey',
 
29
                    115 : 'Light Grey',
 
30
                    }
 
31
    maxThickness = 16
 
32
 
 
33
 
 
34
    def __init__(self, parent, ID):
 
35
        wx.Window.__init__(self, parent, ID, style=wx.NO_FULL_REPAINT_ON_RESIZE)
 
36
        self.SetBackgroundColour("WHITE")
 
37
        self.listeners = []
 
38
        self.thickness = 1
 
39
        self.SetColour("Black")
 
40
        self.lines = []
 
41
        self.pos = wx.Point(0,0)
 
42
        self.MakeMenu()
 
43
 
 
44
        self.InitBuffer()
 
45
 
 
46
        self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL))
 
47
 
 
48
        # hook some mouse events
 
49
        self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
 
50
        self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
 
51
        self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
 
52
        self.Bind(wx.EVT_MOTION, self.OnMotion)
 
53
 
 
54
        # the window resize event and idle events for managing the buffer
 
55
        self.Bind(wx.EVT_SIZE, self.OnSize)
 
56
        self.Bind(wx.EVT_IDLE, self.OnIdle)
 
57
 
 
58
        # and the refresh event
 
59
        self.Bind(wx.EVT_PAINT, self.OnPaint)
 
60
 
 
61
        # When the window is destroyed, clean up resources.
 
62
        self.Bind(wx.EVT_WINDOW_DESTROY, self.Cleanup)
 
63
 
 
64
 
 
65
    def Cleanup(self, evt):
 
66
        if hasattr(self, "menu"):
 
67
            self.menu.Destroy()
 
68
            del self.menu
 
69
 
 
70
 
 
71
    def InitBuffer(self):
 
72
        """Initialize the bitmap used for buffering the display."""
 
73
        size = self.GetClientSize()
 
74
        self.buffer = wx.EmptyBitmap(max(1,size.width), max(1,size.height))
 
75
        dc = wx.BufferedDC(None, self.buffer)
 
76
        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
 
77
        dc.Clear()
 
78
        self.DrawLines(dc)
 
79
        self.reInitBuffer = False
 
80
 
 
81
 
 
82
    def SetColour(self, colour):
 
83
        """Set a new colour and make a matching pen"""
 
84
        self.colour = colour
 
85
        self.pen = wx.Pen(self.colour, self.thickness, wx.SOLID)
 
86
        self.Notify()
 
87
 
 
88
 
 
89
    def SetThickness(self, num):
 
90
        """Set a new line thickness and make a matching pen"""
 
91
        self.thickness = num
 
92
        self.pen = wx.Pen(self.colour, self.thickness, wx.SOLID)
 
93
        self.Notify()
 
94
 
 
95
 
 
96
    def GetLinesData(self):
 
97
        return self.lines[:]
 
98
 
 
99
 
 
100
    def SetLinesData(self, lines):
 
101
        self.lines = lines[:]
 
102
        self.InitBuffer()
 
103
        self.Refresh()
 
104
 
 
105
 
 
106
    def MakeMenu(self):
 
107
        """Make a menu that can be popped up later"""
 
108
        menu = wx.Menu()
 
109
        keys = self.menuColours.keys()
 
110
        keys.sort()
 
111
        for k in keys:
 
112
            text = self.menuColours[k]
 
113
            menu.Append(k, text, kind=wx.ITEM_CHECK)
 
114
        self.Bind(wx.EVT_MENU_RANGE, self.OnMenuSetColour, id=100, id2=200)
 
115
        self.Bind(wx.EVT_UPDATE_UI_RANGE, self.OnCheckMenuColours, id=100, id2=200)
 
116
        menu.Break()
 
117
 
 
118
        for x in range(1, self.maxThickness+1):
 
119
            menu.Append(x, str(x), kind=wx.ITEM_CHECK)
 
120
 
 
121
        self.Bind(wx.EVT_MENU_RANGE, self.OnMenuSetThickness, id=1, id2=self.maxThickness)
 
122
        self.Bind(wx.EVT_UPDATE_UI_RANGE, self.OnCheckMenuThickness, id=1, id2=self.maxThickness)
 
123
        self.menu = menu
 
124
 
 
125
 
 
126
    # These two event handlers are called before the menu is displayed
 
127
    # to determine which items should be checked.
 
128
    def OnCheckMenuColours(self, event):
 
129
        text = self.menuColours[event.GetId()]
 
130
        if text == self.colour:
 
131
            event.Check(True)
 
132
            event.SetText(text.upper())
 
133
        else:
 
134
            event.Check(False)
 
135
            event.SetText(text)
 
136
 
 
137
    def OnCheckMenuThickness(self, event):
 
138
        if event.GetId() == self.thickness:
 
139
            event.Check(True)
 
140
        else:
 
141
            event.Check(False)
 
142
 
 
143
 
 
144
    def OnLeftDown(self, event):
 
145
        """called when the left mouse button is pressed"""
 
146
        self.curLine = []
 
147
        self.pos = event.GetPosition()
 
148
        self.CaptureMouse()
 
149
 
 
150
 
 
151
    def OnLeftUp(self, event):
 
152
        """called when the left mouse button is released"""
 
153
        if self.HasCapture():
 
154
            self.lines.append( (self.colour, self.thickness, self.curLine) )
 
155
            self.curLine = []
 
156
            self.ReleaseMouse()
 
157
 
 
158
 
 
159
    def OnRightUp(self, event):
 
160
        """called when the right mouse button is released, will popup the menu"""
 
161
        pt = event.GetPosition()
 
162
        self.PopupMenu(self.menu, pt)
 
163
 
 
164
 
 
165
 
 
166
    def OnMotion(self, event):
 
167
        """
 
168
        Called when the mouse is in motion.  If the left button is
 
169
        dragging then draw a line from the last event position to the
 
170
        current one.  Save the coordinants for redraws.
 
171
        """
 
172
        if event.Dragging() and event.LeftIsDown():
 
173
            dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
 
174
            dc.BeginDrawing()
 
175
            dc.SetPen(self.pen)
 
176
            pos = event.GetPosition()
 
177
            coords = (self.pos.x, self.pos.y, pos.x, pos.y)
 
178
            self.curLine.append(coords)
 
179
            dc.DrawLine(*coords)
 
180
            self.pos = pos
 
181
            dc.EndDrawing()
 
182
 
 
183
 
 
184
    def OnSize(self, event):
 
185
        """
 
186
        Called when the window is resized.  We set a flag so the idle
 
187
        handler will resize the buffer.
 
188
        """
 
189
        self.reInitBuffer = True
 
190
 
 
191
 
 
192
    def OnIdle(self, event):
 
193
        """
 
194
        If the size was changed then resize the bitmap used for double
 
195
        buffering to match the window size.  We do it in Idle time so
 
196
        there is only one refresh after resizing is done, not lots while
 
197
        it is happening.
 
198
        """
 
199
        if self.reInitBuffer:
 
200
            self.InitBuffer()
 
201
            self.Refresh(False)
 
202
 
 
203
 
 
204
    def OnPaint(self, event):
 
205
        """
 
206
        Called when the window is exposed.
 
207
        """
 
208
        # Create a buffered paint DC.  It will create the real
 
209
        # wx.PaintDC and then blit the bitmap to it when dc is
 
210
        # deleted.  Since we don't need to draw anything else
 
211
        # here that's all there is to it.
 
212
        dc = wx.BufferedPaintDC(self, self.buffer)
 
213
 
 
214
 
 
215
    def DrawLines(self, dc):
 
216
        """
 
217
        Redraws all the lines that have been drawn already.
 
218
        """
 
219
        dc.BeginDrawing()
 
220
        for colour, thickness, line in self.lines:
 
221
            pen = wx.Pen(colour, thickness, wx.SOLID)
 
222
            dc.SetPen(pen)
 
223
            for coords in line:
 
224
                dc.DrawLine(*coords)
 
225
        dc.EndDrawing()
 
226
 
 
227
 
 
228
    # Event handlers for the popup menu, uses the event ID to determine
 
229
    # the colour or the thickness to set.
 
230
    def OnMenuSetColour(self, event):
 
231
        self.SetColour(self.menuColours[event.GetId()])
 
232
 
 
233
    def OnMenuSetThickness(self, event):
 
234
        self.SetThickness(event.GetId())
 
235
 
 
236
 
 
237
    # Observer pattern.  Listeners are registered and then notified
 
238
    # whenever doodle settings change.
 
239
    def AddListener(self, listener):
 
240
        self.listeners.append(listener)
 
241
 
 
242
    def Notify(self):
 
243
        for other in self.listeners:
 
244
            other.Update(self.colour, self.thickness)
 
245
 
 
246
 
 
247
#----------------------------------------------------------------------
 
248
 
 
249
class DoodleFrame(wx.Frame):
 
250
    def __init__(self, parent):
 
251
        wx.Frame.__init__(self, parent, -1, "Doodle Frame", size=(800,600),
 
252
                         style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
 
253
        doodle = DoodleWindow(self, -1)
 
254
 
 
255
#----------------------------------------------------------------------
 
256
 
 
257
if __name__ == '__main__':
 
258
    app = wx.PySimpleApp()
 
259
    frame = DoodleFrame(None)
 
260
    frame.Show(True)
 
261
    app.MainLoop()
 
262