]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/doodle/superdoodle.py
wxHtmlHistoryItem needs not be wxObject
[wxWidgets.git] / wxPython / samples / doodle / superdoodle.py
1 # superdoodle.py
2
3 """
4 This module implements the SuperDoodle demo application. It takes the
5 DoodleWindow previously presented and reuses it in a much more
6 intelligent Frame. This one has a menu and a statusbar, is able to
7 save and reload doodles, clear the workspace, and has a simple control
8 panel for setting color and line thickness in addition to the popup
9 menu that DoodleWindow provides. There is also a nice About dialog
10 implmented using an wxHtmlWindow.
11 """
12
13 from wxPython.wx import *
14 from doodle import DoodleWindow
15
16 import os, cPickle
17
18
19 #----------------------------------------------------------------------
20
21 idNEW = 11001
22 idOPEN = 11002
23 idSAVE = 11003
24 idSAVEAS = 11004
25 idCLEAR = 11005
26 idEXIT = 11006
27 idABOUT = 11007
28
29
30 class 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):
38 wxFrame.__init__(self, parent, -1, self.title, size=(800,600),
39 style=wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
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
59 EVT_CLOSE(self, self.OnCloseWindow)
60
61
62 def OnCloseWindow(self, event):
63 self.doodle.Cleanup()
64 self.Destroy()
65
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):
120 dlg = wxFileDialog(self, "Open doodle file...", os.getcwd(),
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):
137 dlg = wxFileDialog(self, "Save doodle as...", os.getcwd(),
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
169 class 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
263 class 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
303 class 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"
310 cellpadding="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
317 will hopefully teach you a thing or two. Just follow these simple
318 instructions: </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
365 class 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
375 if __name__ == '__main__':
376 app = DoodleApp(0)
377 app.MainLoop()