]>
Commit | Line | Data |
---|---|---|
1 | import wx | |
2 | import wx.html | |
3 | import cPickle | |
4 | import os | |
5 | from wx.lib import buttons | |
6 | ||
7 | from example1 import SketchWindow | |
8 | ||
9 | class SketchFrame(wx.Frame): | |
10 | def __init__(self, parent): | |
11 | self.title = "Sketch Frame" | |
12 | wx.Frame.__init__(self, parent, -1, self.title, | |
13 | size=(800,600)) | |
14 | self.filename = "" | |
15 | self.sketch = SketchWindow(self, -1) | |
16 | wx.EVT_MOTION(self.sketch, self.OnSketchMotion) | |
17 | self.initStatusBar() | |
18 | self.createMenuBar() | |
19 | self.createToolBar() | |
20 | self.createPanel() | |
21 | ||
22 | def createPanel(self): | |
23 | controlPanel = ControlPanel(self, -1, self.sketch) | |
24 | box = wx.BoxSizer(wx.HORIZONTAL) | |
25 | box.Add(controlPanel, 0, wx.EXPAND) | |
26 | box.Add(self.sketch, 1, wx.EXPAND) | |
27 | self.SetSizer(box) | |
28 | ||
29 | def initStatusBar(self): | |
30 | self.statusbar = self.CreateStatusBar() | |
31 | self.statusbar.SetFieldsCount(3) | |
32 | self.statusbar.SetStatusWidths([-1, -2, -3]) | |
33 | ||
34 | def OnSketchMotion(self, event): | |
35 | self.statusbar.SetStatusText("Pos: %s" % | |
36 | str(event.GetPositionTuple()), 0) | |
37 | self.statusbar.SetStatusText("Current Pts: %s" % | |
38 | len(self.sketch.curLine), 1) | |
39 | self.statusbar.SetStatusText("Line Count: %s" % | |
40 | len(self.sketch.lines), 2) | |
41 | event.Skip() | |
42 | ||
43 | def menuData(self): | |
44 | return [("&File", ( | |
45 | ("&New", "New Sketch file", self.OnNew), | |
46 | ("&Open", "Open sketch file", self.OnOpen), | |
47 | ("&Save", "Save sketch file", self.OnSave), | |
48 | ("", "", ""), | |
49 | ("&Color", ( | |
50 | ("&Black", "", self.OnColor, wx.ITEM_RADIO), | |
51 | ("&Red", "", self.OnColor, wx.ITEM_RADIO), | |
52 | ("&Green", "", self.OnColor, wx.ITEM_RADIO), | |
53 | ("&Blue", "", self.OnColor, wx.ITEM_RADIO), | |
54 | ("&Other...", "", self.OnOtherColor, wx.ITEM_RADIO))), | |
55 | ("", "", ""), | |
56 | ("About...", "Show about window", self.OnAbout), | |
57 | ("&Quit", "Quit", self.OnCloseWindow)))] | |
58 | ||
59 | def createMenuBar(self): | |
60 | menuBar = wx.MenuBar() | |
61 | for eachMenuData in self.menuData(): | |
62 | menuLabel = eachMenuData[0] | |
63 | menuItems = eachMenuData[1] | |
64 | menuBar.Append(self.createMenu(menuItems), menuLabel) | |
65 | self.SetMenuBar(menuBar) | |
66 | ||
67 | def createMenu(self, menuData): | |
68 | menu = wx.Menu() | |
69 | for eachItem in menuData: | |
70 | if len(eachItem) == 2: | |
71 | label = eachItem[0] | |
72 | subMenu = self.createMenu(eachItem[1]) | |
73 | menu.AppendMenu(wx.NewId(), label, subMenu) | |
74 | else: | |
75 | self.createMenuItem(menu, *eachItem) | |
76 | return menu | |
77 | ||
78 | def createMenuItem(self, menu, label, status, handler, kind=wx.ITEM_NORMAL): | |
79 | if not label: | |
80 | menu.AppendSeparator() | |
81 | return | |
82 | menuItem = menu.Append(-1, label, status, kind) | |
83 | self.Bind(wx.EVT_MENU, handler, menuItem) | |
84 | ||
85 | def createToolBar(self): | |
86 | toolbar = self.CreateToolBar() | |
87 | for each in self.toolbarData(): | |
88 | self.createSimpleTool(toolbar, *each) | |
89 | toolbar.AddSeparator() | |
90 | for each in self.toolbarColorData(): | |
91 | self.createColorTool(toolbar, each) | |
92 | toolbar.Realize() | |
93 | ||
94 | def createSimpleTool(self, toolbar, label, filename, help, handler): | |
95 | if not label: | |
96 | toolbar.AddSeparator() | |
97 | return | |
98 | bmp = wx.Image(filename, wx.BITMAP_TYPE_BMP).ConvertToBitmap() | |
99 | tool = toolbar.AddSimpleTool(-1, bmp, label, help) | |
100 | self.Bind(wx.EVT_MENU, handler, tool) | |
101 | ||
102 | def toolbarData(self): | |
103 | return (("New", "new.bmp", "Create new sketch", self.OnNew), | |
104 | ("", "", "", ""), | |
105 | ("Open", "open.bmp", "Open existing sketch", self.OnOpen), | |
106 | ("Save", "save.bmp", "Save existing sketch", self.OnSave)) | |
107 | ||
108 | def createColorTool(self, toolbar, color): | |
109 | bmp = self.MakeBitmap(color) | |
110 | tool = toolbar.AddRadioTool(-1, bmp, shortHelp=color) | |
111 | self.Bind(wx.EVT_MENU, self.OnColor, tool) | |
112 | ||
113 | def MakeBitmap(self, color): | |
114 | bmp = wx.EmptyBitmap(16, 15) | |
115 | dc = wx.MemoryDC() | |
116 | dc.SelectObject(bmp) | |
117 | dc.SetBackground(wx.Brush(color)) | |
118 | dc.Clear() | |
119 | dc.SelectObject(wx.NullBitmap) | |
120 | return bmp | |
121 | ||
122 | def toolbarColorData(self): | |
123 | return ("Black", "Red", "Green", "Blue") | |
124 | ||
125 | def OnNew(self, event): pass | |
126 | ||
127 | def OnColor(self, event): | |
128 | menubar = self.GetMenuBar() | |
129 | itemId = event.GetId() | |
130 | item = menubar.FindItemById(itemId) | |
131 | if not item: | |
132 | toolbar = self.GetToolBar() | |
133 | item = toolbar.FindById(itemId) | |
134 | color = item.GetShortHelp() | |
135 | else: | |
136 | color = item.GetLabel() | |
137 | self.sketch.SetColor(color) | |
138 | ||
139 | def OnCloseWindow(self, event): | |
140 | self.Destroy() | |
141 | ||
142 | def SaveFile(self): | |
143 | if self.filename: | |
144 | data = self.sketch.GetLinesData() | |
145 | f = open(self.filename, 'w') | |
146 | cPickle.dump(data, f) | |
147 | f.close() | |
148 | ||
149 | def ReadFile(self): | |
150 | if self.filename: | |
151 | try: | |
152 | f = open(self.filename, 'r') | |
153 | data = cPickle.load(f) | |
154 | f.close() | |
155 | self.sketch.SetLinesData(data) | |
156 | except cPickle.UnpicklingError: | |
157 | wx.MessageBox("%s is not a sketch file." % self.filename, | |
158 | "oops!", style=wx.OK|wx.ICON_EXCLAMATION) | |
159 | ||
160 | wildcard = "Sketch files (*.sketch)|*.sketch|All files (*.*)|*.*" | |
161 | ||
162 | def OnOpen(self, event): | |
163 | dlg = wx.FileDialog(self, "Open sketch file...", os.getcwd(), | |
164 | style=wx.OPEN, wildcard=self.wildcard) | |
165 | if dlg.ShowModal() == wx.ID_OK: | |
166 | self.filename = dlg.GetPath() | |
167 | self.ReadFile() | |
168 | self.SetTitle(self.title + ' -- ' + self.filename) | |
169 | dlg.Destroy() | |
170 | ||
171 | def OnSave(self, event): | |
172 | if not self.filename: | |
173 | self.OnSaveAs(event) | |
174 | else: | |
175 | self.SaveFile() | |
176 | ||
177 | def OnSaveAs(self, event): | |
178 | dlg = wx.FileDialog(self, "Save sketch as...", os.getcwd(), | |
179 | style=wx.SAVE | wx.OVERWRITE_PROMPT, | |
180 | wildcard = self.wildcard) | |
181 | if dlg.ShowModal() == wx.ID_OK: | |
182 | filename = dlg.GetPath() | |
183 | if not os.path.splitext(filename)[1]: | |
184 | filename = filename + '.sketch' | |
185 | self.filename = filename | |
186 | self.SaveFile() | |
187 | self.SetTitle(self.title + ' -- ' + self.filename) | |
188 | dlg.Destroy() | |
189 | ||
190 | def OnOtherColor(self, event): | |
191 | dlg = wx.ColourDialog(frame) | |
192 | dlg.GetColourData().SetChooseFull(True) | |
193 | if dlg.ShowModal() == wx.ID_OK: | |
194 | self.sketch.SetColor(dlg.GetColourData().GetColour()) | |
195 | dlg.Destroy() | |
196 | ||
197 | def OnAbout(self, event): | |
198 | dlg = SketchAbout(self) | |
199 | dlg.ShowModal() | |
200 | dlg.Destroy() | |
201 | ||
202 | ||
203 | class SketchAbout(wx.Dialog): | |
204 | text = ''' | |
205 | <html> | |
206 | <body bgcolor="#ACAA60"> | |
207 | <center><table bgcolor="#455481" width="100%" cellspacing="0" | |
208 | cellpadding="0" border="1"> | |
209 | <tr> | |
210 | <td align="center"><h1>Sketch!</h1></td> | |
211 | </tr> | |
212 | </table> | |
213 | </center> | |
214 | <p><b>Sketch</b> is a demonstration program for <b>wxPython In Action</b> | |
215 | Chapter 7. It is based on the SuperDoodle demo included with wxPython, | |
216 | available at http://www.wxpython.org/ | |
217 | </p> | |
218 | ||
219 | <p><b>SuperDoodle</b> and <b>wxPython</b> are brought to you by | |
220 | <b>Robin Dunn</b> and <b>Total Control Software</b>, Copyright | |
221 | © 1997-2006.</p> | |
222 | </body> | |
223 | </html> | |
224 | ''' | |
225 | ||
226 | def __init__(self, parent): | |
227 | wx.Dialog.__init__(self, parent, -1, 'About Sketch', | |
228 | size=(440, 400) ) | |
229 | ||
230 | html = wx.html.HtmlWindow(self) | |
231 | html.SetPage(self.text) | |
232 | button = wx.Button(self, wx.ID_OK, "Okay") | |
233 | ||
234 | sizer = wx.BoxSizer(wx.VERTICAL) | |
235 | sizer.Add(html, 1, wx.EXPAND|wx.ALL, 5) | |
236 | sizer.Add(button, 0, wx.ALIGN_CENTER|wx.ALL, 5) | |
237 | ||
238 | self.SetSizer(sizer) | |
239 | self.Layout() | |
240 | ||
241 | ||
242 | ||
243 | class ControlPanel(wx.Panel): | |
244 | ||
245 | BMP_SIZE = 16 | |
246 | BMP_BORDER = 3 | |
247 | NUM_COLS = 4 | |
248 | SPACING = 4 | |
249 | ||
250 | colorList = ('Black', 'Yellow', 'Red', 'Green', 'Blue', 'Purple', | |
251 | 'Brown', 'Aquamarine', 'Forest Green', 'Light Blue', | |
252 | 'Goldenrod', 'Cyan', 'Orange', 'Navy', 'Dark Grey', | |
253 | 'Light Grey') | |
254 | maxThickness = 16 | |
255 | ||
256 | def __init__(self, parent, ID, sketch): | |
257 | wx.Panel.__init__(self, parent, ID, style=wx.RAISED_BORDER) | |
258 | self.sketch = sketch | |
259 | buttonSize = (self.BMP_SIZE + 2 * self.BMP_BORDER, | |
260 | self.BMP_SIZE + 2 * self.BMP_BORDER) | |
261 | colorGrid = self.createColorGrid(parent, buttonSize) | |
262 | thicknessGrid = self.createThicknessGrid(buttonSize) | |
263 | self.layout(colorGrid, thicknessGrid) | |
264 | ||
265 | def createColorGrid(self, parent, buttonSize): | |
266 | self.colorMap = {} | |
267 | self.colorButtons = {} | |
268 | colorGrid = wx.GridSizer(cols=self.NUM_COLS, hgap=2, vgap=2) | |
269 | for eachColor in self.colorList: | |
270 | bmp = parent.MakeBitmap(eachColor) | |
271 | b = buttons.GenBitmapToggleButton(self, -1, bmp, size=buttonSize) | |
272 | b.SetBezelWidth(1) | |
273 | b.SetUseFocusIndicator(False) | |
274 | self.Bind(wx.EVT_BUTTON, self.OnSetColour, b) | |
275 | colorGrid.Add(b, 0) | |
276 | self.colorMap[b.GetId()] = eachColor | |
277 | self.colorButtons[eachColor] = b | |
278 | self.colorButtons[self.colorList[0]].SetToggle(True) | |
279 | return colorGrid | |
280 | ||
281 | def createThicknessGrid(self, buttonSize): | |
282 | self.thicknessIdMap = {} | |
283 | self.thicknessButtons = {} | |
284 | thicknessGrid = wx.GridSizer(cols=self.NUM_COLS, hgap=2, vgap=2) | |
285 | for x in range(1, self.maxThickness + 1): | |
286 | b = buttons.GenToggleButton(self, -1, str(x), size=buttonSize) | |
287 | b.SetBezelWidth(1) | |
288 | b.SetUseFocusIndicator(False) | |
289 | self.Bind(wx.EVT_BUTTON, self.OnSetThickness, b) | |
290 | thicknessGrid.Add(b, 0) | |
291 | self.thicknessIdMap[b.GetId()] = x | |
292 | self.thicknessButtons[x] = b | |
293 | self.thicknessButtons[1].SetToggle(True) | |
294 | return thicknessGrid | |
295 | ||
296 | def layout(self, colorGrid, thicknessGrid): | |
297 | box = wx.BoxSizer(wx.VERTICAL) | |
298 | box.Add(colorGrid, 0, wx.ALL, self.SPACING) | |
299 | box.Add(thicknessGrid, 0, wx.ALL, self.SPACING) | |
300 | self.SetSizer(box) | |
301 | box.Fit(self) | |
302 | ||
303 | def OnSetColour(self, event): | |
304 | color = self.colorMap[event.GetId()] | |
305 | if color != self.sketch.color: | |
306 | self.colorButtons[self.sketch.color].SetToggle(False) | |
307 | self.sketch.SetColor(color) | |
308 | ||
309 | def OnSetThickness(self, event): | |
310 | thickness = self.thicknessIdMap[event.GetId()] | |
311 | if thickness != self.sketch.thickness: | |
312 | self.thicknessButtons[self.sketch.thickness].SetToggle(False) | |
313 | self.sketch.SetThickness(thickness) | |
314 | ||
315 | ||
316 | class SketchApp(wx.App): | |
317 | ||
318 | def OnInit(self): | |
319 | bmp = wx.Image("splash.png").ConvertToBitmap() | |
320 | wx.SplashScreen(bmp, wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT, | |
321 | 1000, None, -1) | |
322 | wx.Yield() | |
323 | ||
324 | frame = SketchFrame(None) | |
325 | frame.Show(True) | |
326 | self.SetTopWindow(frame) | |
327 | return True | |
328 | ||
329 | if __name__ == '__main__': | |
330 | app = SketchApp(False) | |
331 | app.MainLoop() |