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