]> git.saurik.com Git - wxWidgets.git/blame - wxPython/samples/doodle/superdoodle.py
corrected assert even better
[wxWidgets.git] / wxPython / samples / doodle / superdoodle.py
CommitLineData
c12bc4de
RD
1# superdoodle.py
2
3"""
4This module implements the SuperDoodle demo application. It takes the
5DoodleWindow previously presented and reuses it in a much more
6intelligent Frame. This one has a menu and a statusbar, is able to
7save and reload doodles, clear the workspace, and has a simple control
8panel for setting color and line thickness in addition to the popup
9menu that DoodleWindow provides. There is also a nice About dialog
10implmented using an wxHtmlWindow.
11"""
12
13from wxPython.wx import *
14from doodle import DoodleWindow
15
16import os, cPickle
17
18
19#----------------------------------------------------------------------
20
21idNEW = 11001
22idOPEN = 11002
23idSAVE = 11003
24idSAVEAS = 11004
25idCLEAR = 11005
26idEXIT = 11006
27idABOUT = 11007
28
29
30class DoodleFrame(wxFrame):
31 """
32 A DoodleFrame contains a DoodleWindow and a ControlPanel and manages
33 their layout with a wxBoxSizer. A menu and associated event handlers
34 provides for saving a doodle to a file, etc.
35 """
36 title = "Do a doodle"
37 def __init__(self, parent):
9de06a79
RD
38 wxFrame.__init__(self, parent, -1, self.title, size=(800,600),
39 style=wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
c12bc4de
RD
40 self.CreateStatusBar()
41 self.MakeMenu()
42 self.filename = None
43
44 self.doodle = DoodleWindow(self, -1)
45 cPanel = ControlPanel(self, -1, self.doodle)
46
47 # Create a sizer to layout the two windows side-by-side.
48 # Both will grow vertically, the doodle window will grow
49 # horizontally as well.
50 box = wxBoxSizer(wxHORIZONTAL)
51 box.Add(cPanel, 0, wxEXPAND)
52 box.Add(self.doodle, 1, wxEXPAND)
53
54 # Tell the frame that it should layout itself in response to
55 # size events.
56 self.SetAutoLayout(true)
57 self.SetSizer(box)
58
9de06a79
RD
59 EVT_CLOSE(self, self.OnCloseWindow)
60
61
62 def OnCloseWindow(self, event):
63 self.doodle.Cleanup()
64 self.Destroy()
65
c12bc4de
RD
66
67 def SaveFile(self):
68 if self.filename:
69 data = self.doodle.GetLinesData()
70 f = open(self.filename, 'w')
71 cPickle.dump(data, f)
72 f.close()
73
74
75 def ReadFile(self):
76 if self.filename:
77 try:
78 f = open(self.filename, 'r')
79 data = cPickle.load(f)
80 f.close()
81 self.doodle.SetLinesData(data)
82 except cPickle.UnpicklingError:
83 wxMessageBox("%s is not a doodle file." % self.filename,
84 "oops!", style=wxOK|wxICON_EXCLAMATION)
85
86
87 def MakeMenu(self):
88 # create the file menu
89 menu1 = wxMenu()
90 menu1.Append(idOPEN, "&Open", "Open a doodle file")
91 menu1.Append(idSAVE, "&Save", "Save the doodle")
92 menu1.Append(idSAVEAS, "Save &As", "Save the doodle in a new file")
93 menu1.AppendSeparator()
94 menu1.Append(idCLEAR, "&Clear", "Clear the current doodle")
95 menu1.AppendSeparator()
96 menu1.Append(idEXIT, "E&xit", "Terminate the application")
97
98 # and the help menu
99 menu2 = wxMenu()
100 menu2.Append(idABOUT, "&About", "Display the gratuitous 'about this app' thingamajig")
101
102 # and add them to a menubar
103 menuBar = wxMenuBar()
104 menuBar.Append(menu1, "&File")
105 menuBar.Append(menu2, "&Help")
106 self.SetMenuBar(menuBar)
107
108 EVT_MENU(self, idOPEN, self.OnMenuOpen)
109 EVT_MENU(self, idSAVE, self.OnMenuSave)
110 EVT_MENU(self, idSAVEAS, self.OnMenuSaveAs)
111 EVT_MENU(self, idCLEAR, self.OnMenuClear)
112 EVT_MENU(self, idEXIT, self.OnMenuExit)
113 EVT_MENU(self, idABOUT, self.OnMenuAbout)
114
115
116
117 wildcard = "Doodle files (*.ddl)|*.ddl|All files (*.*)|*.*"
118
119 def OnMenuOpen(self, event):
7114b9fa 120 dlg = wxFileDialog(self, "Open doodle file...", os.getcwd(),
c12bc4de
RD
121 style=wxOPEN, wildcard = self.wildcard)
122 if dlg.ShowModal() == wxID_OK:
123 self.filename = dlg.GetPath()
124 self.ReadFile()
125 self.SetTitle(self.title + ' -- ' + self.filename)
126 dlg.Destroy()
127
128
129 def OnMenuSave(self, event):
130 if not self.filename:
131 self.OnMenuSaveAs(event)
132 else:
133 self.SaveFile()
134
135
136 def OnMenuSaveAs(self, event):
7114b9fa 137 dlg = wxFileDialog(self, "Save doodle as...", os.getcwd(),
c12bc4de
RD
138 style=wxSAVE | wxOVERWRITE_PROMPT,
139 wildcard = self.wildcard)
140 if dlg.ShowModal() == wxID_OK:
141 filename = dlg.GetPath()
142 if not os.path.splitext(filename)[1]:
143 filename = filename + '.ddl'
144 self.filename = filename
145 self.SaveFile()
146 self.SetTitle(self.title + ' -- ' + self.filename)
147 dlg.Destroy()
148
149
150 def OnMenuClear(self, event):
151 self.doodle.SetLinesData([])
152 self.SetTitle(self.title)
153
154
155 def OnMenuExit(self, event):
156 self.Close()
157
158
159 def OnMenuAbout(self, event):
160 dlg = DoodleAbout(self)
161 dlg.ShowModal()
162 dlg.Destroy()
163
164
165
166#----------------------------------------------------------------------
167
168
169class ControlPanel(wxPanel):
170 """
171 This class implements a very simple control panel for the DoodleWindow.
172 It creates buttons for each of the colours and thickneses supported by
173 the DoodleWindow, and event handlers to set the selected values. There is
174 also a little window that shows an example doodleLine in the selected
175 values. Nested sizers are used for layout.
176 """
177 def __init__(self, parent, ID, doodle):
178 wxPanel.__init__(self, parent, ID, style=wxRAISED_BORDER)
179
180 numCols = 4
181 spacing = 4
182
183 # Make a grid of buttons for each colour. Attach each button
184 # event to self.OnSetColour. The button ID is the same as the
185 # key in the colour dictionary.
186 colours = doodle.menuColours
187 keys = colours.keys()
188 keys.sort()
189 cGrid = wxGridSizer(cols=numCols, hgap=2, vgap=2)
190 for k in keys:
191 bmp = self.MakeBitmap(wxNamedColour(colours[k]))
192 b = wxBitmapButton(self, k, bmp)
193 EVT_BUTTON(self, k, self.OnSetColour)
194 cGrid.Add(b, 0)
195
196 # Save the button size so we can use it for the number buttons
197 btnSize = b.GetSize()
198
199 # Make a grid of buttons for the thicknesses. Attach each button
200 # event to self.OnSetThickness. The button ID is the same as the
201 # thickness value.
202 tGrid = wxGridSizer(cols=numCols, hgap=2, vgap=2)
203 for x in range(1, doodle.maxThickness+1):
204 b = wxButton(self, x, str(x), size=btnSize)
205 EVT_BUTTON(self, x, self.OnSetThickness)
206 tGrid.Add(b, 0)
207
208 # Make a colour indicator window, it is registerd as a listener
209 # with the doodle window so it will be notified when the settings
210 # change
211 ci = ColourIndicator(self)
212 doodle.AddListener(ci)
213 doodle.Notify()
214 self.doodle = doodle
215
216 # Make a box sizer and put the two grids and the indicator
217 # window in it.
218 box = wxBoxSizer(wxVERTICAL)
219 box.Add(cGrid, 0, wxALL, spacing)
220 box.Add(tGrid, 0, wxALL, spacing)
221 box.Add(ci, 0, wxEXPAND|wxALL, spacing)
222 self.SetSizer(box)
223 self.SetAutoLayout(true)
224
225 # Resize this window so it is just large enough for the
226 # minimum requirements of the sizer.
227 box.Fit(self)
228
229
230
231 def MakeBitmap(self, colour):
232 """
233 We can create a bitmap of whatever we want by simply selecting
234 it into a wxMemoryDC and drawing on it. In this case we just set
235 a background brush and clear the dc.
236 """
237 bmp = wxEmptyBitmap(16,16)
238 dc = wxMemoryDC()
239 dc.SelectObject(bmp)
240 dc.SetBackground(wxBrush(colour))
241 dc.Clear()
242 dc.SelectObject(wxNullBitmap)
243 return bmp
244
245
246 def OnSetColour(self, event):
247 """
248 Use the event ID to get the colour, set that colour in the doodle.
249 """
250 colour = self.doodle.menuColours[event.GetId()]
251 self.doodle.SetColour(colour)
252
253
254 def OnSetThickness(self, event):
255 """
256 Use the event ID to set the thickness in the doodle.
257 """
258 self.doodle.SetThickness(event.GetId())
259
260
261#----------------------------------------------------------------------
262
263class ColourIndicator(wxWindow):
264 """
265 An instance of this class is used on the ControlPanel to show
266 a sample of what the current doodle line will look like.
267 """
268 def __init__(self, parent):
269 wxWindow.__init__(self, parent, -1, style=wxSUNKEN_BORDER)
270 self.SetBackgroundColour(wxWHITE)
271 self.SetSize(wxSize(-1, 40))
272 self.colour = self.thickness = None
273 EVT_PAINT(self, self.OnPaint)
274
275
276 def Update(self, colour, thickness):
277 """
278 The doodle window calls this method any time the colour
279 or line thickness changes.
280 """
281 self.colour = colour
282 self.thickness = thickness
283 self.Refresh() # generate a paint event
284
285
286 def OnPaint(self, event):
287 """
288 This method is called when all or part of the window needs to be
289 redrawn.
290 """
291 dc = wxPaintDC(self)
292 if self.colour:
293 sz = self.GetClientSize()
294 pen = wxPen(wxNamedColour(self.colour), self.thickness)
295 dc.BeginDrawing()
296 dc.SetPen(pen)
297 dc.DrawLine(10, sz.height/2, sz.width-10, sz.height/2)
298 dc.EndDrawing()
299
300
301#----------------------------------------------------------------------
302
303class DoodleAbout(wxDialog):
304 """ An about box that uses an HTML window """
305
306 text = '''
307<html>
308<body bgcolor="#ACAA60">
309<center><table bgcolor="#455481" width="100%" cellspacing="0"
310cellpadding="0" border="1">
311<tr>
312 <td align="center"><h1>SuperDoodle</h1></td>
313</tr>
314</table>
315</center>
316<p><b>SuperDoodle</b> is a demonstration program for <b>wxPython</b> that
317will hopefully teach you a thing or two. Just follow these simple
318instructions: </p>
319<p>
320<ol>
321 <li><b>Read</b> the Source...
322 <li><b>Learn</b>...
323 <li><b>Do!</b>
324</ol>
325
326<p><b>SuperDoodle</b> and <b>wxPython</b> are brought to you by
327<b>Robin Dunn</b> and <b>Total Control Software</b>, Copyright
328&copy; 1997-2001.</p>
329</body>
330</html>
331'''
332
333 def __init__(self, parent):
334 wxDialog.__init__(self, parent, -1, 'About SuperDoodle',
335 size=wxSize(420, 380))
336 from wxPython.html import wxHtmlWindow
337
338 html = wxHtmlWindow(self, -1)
339 html.SetPage(self.text)
340 button = wxButton(self, wxID_OK, "Okay")
341
342 # constraints for the html window
343 lc = wxLayoutConstraints()
344 lc.top.SameAs(self, wxTop, 5)
345 lc.left.SameAs(self, wxLeft, 5)
346 lc.bottom.SameAs(button, wxTop, 5)
347 lc.right.SameAs(self, wxRight, 5)
348 html.SetConstraints(lc)
349
350 # constraints for the button
351 lc = wxLayoutConstraints()
352 lc.bottom.SameAs(self, wxBottom, 5)
353 lc.centreX.SameAs(self, wxCentreX)
354 lc.width.AsIs()
355 lc.height.AsIs()
356 button.SetConstraints(lc)
357
358 self.SetAutoLayout(true)
359 self.Layout()
360 self.CentreOnParent(wxBOTH)
361
362
363#----------------------------------------------------------------------
364
365class DoodleApp(wxApp):
366 def OnInit(self):
367 frame = DoodleFrame(None)
368 frame.Show(true)
369 self.SetTopWindow(frame)
370 return true
371
372
373#----------------------------------------------------------------------
374
375if __name__ == '__main__':
376 app = DoodleApp(0)
377 app.MainLoop()