blob: bbf1448343d05fbc669e9dc465e2c6df301d3cb9 [file] [log] [blame]
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +00001"A sort of application framework for the Mac"
2
Jack Jansen7a583361995-08-14 12:39:54 +00003DEBUG=0
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +00004
5import MacOS
6import traceback
7
8from addpack import addpack
Jack Jansene4b40381995-07-17 13:25:15 +00009addpack('Tools')
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +000010addpack('bgen')
11addpack('ae')
Jack Jansen7a583361995-08-14 12:39:54 +000012addpack('ctl')
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +000013addpack('dlg')
14addpack('evt')
15addpack('menu')
Jack Jansen7a583361995-08-14 12:39:54 +000016addpack('qd')
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +000017#addpack('res')
18#addpack('snd')
19addpack('win')
20
21from AE import *
22from AppleEvents import *
Jack Jansen7a583361995-08-14 12:39:54 +000023from Ctl import *
24from Controls import *
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +000025from Dlg import *
26from Dialogs import *
27from Evt import *
28from Events import *
29from Menu import *
30from Menus import *
Jack Jansen7a583361995-08-14 12:39:54 +000031from Qd import *
32from QuickDraw import *
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +000033#from Res import *
34#from Resources import *
35#from Snd import *
36#from Sound import *
37from Win import *
38from Windows import *
39
40import EasyDialogs
41
42kHighLevelEvent = 23 # Don't know what header file this should come from
43
44
45# Map event 'what' field to strings
46eventname = {}
47eventname[1] = 'mouseDown'
48eventname[2] = 'mouseUp'
49eventname[3] = 'keyDown'
50eventname[4] = 'keyUp'
51eventname[5] = 'autoKey'
52eventname[6] = 'updateEvt'
53eventname[7] = 'diskEvt'
54eventname[8] = 'activateEvt'
55eventname[15] = 'osEvt'
56eventname[23] = 'kHighLevelEvent'
57
58# Map part codes returned by WhichWindow() to strings
59partname = {}
60partname[0] = 'inDesk'
61partname[1] = 'inMenuBar'
62partname[2] = 'inSysWindow'
63partname[3] = 'inContent'
64partname[4] = 'inDrag'
65partname[5] = 'inGrow'
66partname[6] = 'inGoAway'
67partname[7] = 'inZoomIn'
68partname[8] = 'inZoomOut'
69
70# A rectangle that's bigger than the screen,
71# but not so big that adding the screen size to it will cause 16-bit overflow
72everywhere = (-16000, -16000, 16000, 16000)
73
74
75class Application:
76
77 "Application framework -- your application should be a derived class"
78
79 def __init__(self):
Jack Jansen7e0da901995-08-17 14:18:20 +000080 self._windows = {}
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +000081 self.makemenubar()
82
83 def makemenubar(self):
84 self.menubar = MenuBar()
85 AppleMenu(self.menubar, self.getabouttext(), self.do_about)
86 self.makeusermenus()
Jack Jansenc8a99491996-01-08 23:50:13 +000087
88 def makeusermenus(self):
89 self.filemenu = m = Menu(self.menubar, "File")
90 self._quititem = MenuItem(m, "Quit", "Q", self._quit)
91
92 def _quit(self, *args):
93 raise self
Jack Jansen7e0da901995-08-17 14:18:20 +000094
95 def appendwindow(self, wid, window):
96 self._windows[wid] = window
97
98 def removewindow(self, wid):
99 del self._windows[wid]
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000100
101 def getabouttext(self):
102 return "About %s..." % self.__class__.__name__
103
104 def do_about(self, id, item, window, event):
105 EasyDialogs.Message("Hello, world!" + "\015(%s)" % self.__class__.__name__)
106
107 # The main event loop is broken up in several simple steps.
108 # This is done so you can override each individual part,
109 # if you have a need to do extra processing independent of the
110 # event type.
111 # Normally, however, you'd just define handlers for individual
112 # events.
113 # (XXX I'm not sure if using default parameter values is the right
114 # way to define the mask and wait time passed to WaitNextEvent.)
115
116 def mainloop(self, mask = everyEvent, wait = 0):
117 saveyield = MacOS.EnableAppswitch(self.yield)
118 try:
119 while 1:
120 try:
121 self.do1event(mask, wait)
122 except (Application, SystemExit):
123 break
124 finally:
125 MacOS.EnableAppswitch(saveyield)
126
127 yield = -1
128
129 def do1event(self, mask = everyEvent, wait = 0):
Jack Jansen13dc4f71995-08-31 13:38:01 +0000130 ok, event = self.getevent(mask, wait)
131 if IsDialogEvent(event):
132 if self.do_dialogevent(event):
133 return
134 if ok:
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000135 self.dispatch(event)
Jack Jansen38186781995-11-10 14:48:36 +0000136 else:
137 self.idle()
138
139 def idle(self):
140 pass
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000141
142 def getevent(self, mask = everyEvent, wait = 0):
143 ok, event = WaitNextEvent(mask, wait)
Jack Jansen13dc4f71995-08-31 13:38:01 +0000144 return ok, event
145
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000146 def dispatch(self, event):
147 (what, message, when, where, modifiers) = event
148 if eventname.has_key(what):
149 name = "do_" + eventname[what]
150 else:
151 name = "do_%d" % what
152 try:
153 handler = getattr(self, name)
154 except AttributeError:
155 handler = self.do_unknownevent
156 handler(event)
Jack Jansen7e0da901995-08-17 14:18:20 +0000157
158 def do_dialogevent(self, event):
159 gotone, window, item = DialogSelect(event)
160 if gotone:
161 if self._windows.has_key(window):
Jack Jansen13dc4f71995-08-31 13:38:01 +0000162 self._windows[window].do_itemhit(item, event)
Jack Jansen7e0da901995-08-17 14:18:20 +0000163 else:
164 print 'Dialog event for unknown dialog'
Jack Jansen13dc4f71995-08-31 13:38:01 +0000165 return 1
166 return 0
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000167
168 def do_mouseDown(self, event):
169 (what, message, when, where, modifiers) = event
Jack Jansen7e0da901995-08-17 14:18:20 +0000170 partcode, wid = FindWindow(where)
171
172 #
173 # Find the correct name.
174 #
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000175 if partname.has_key(partcode):
176 name = "do_" + partname[partcode]
177 else:
178 name = "do_%d" % partcode
Jack Jansen7e0da901995-08-17 14:18:20 +0000179
180 if wid == None:
181 # No window, or a non-python window
182 try:
183 handler = getattr(self, name)
184 except AttributeError:
185 # Not menubar or something, so assume someone
186 # else's window
187 MacOS.HandleEvent(event)
188 return
189 elif self._windows.has_key(wid):
190 # It is a window. Hand off to correct window.
191 window = self._windows[wid]
192 try:
193 handler = getattr(window, name)
194 except AttributeError:
195 handler = self.do_unknownpartcode
196 else:
197 # It is a python-toolbox window, but not ours.
198 handler = self.do_unknownwindow
199 handler(partcode, wid, event)
200
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000201 def do_inSysWindow(self, partcode, window, event):
Jack Jansen7a583361995-08-14 12:39:54 +0000202 MacOS.HandleEvent(event)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000203
204 def do_inDesk(self, partcode, window, event):
Jack Jansen7a583361995-08-14 12:39:54 +0000205 MacOS.HandleEvent(event)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000206
207 def do_inMenuBar(self, partcode, window, event):
208 (what, message, when, where, modifiers) = event
209 result = MenuSelect(where)
210 id = (result>>16) & 0xffff # Hi word
211 item = result & 0xffff # Lo word
212 self.do_rawmenu(id, item, window, event)
213
214 def do_rawmenu(self, id, item, window, event):
215 try:
216 self.do_menu(id, item, window, event)
217 finally:
218 HiliteMenu(0)
219
220 def do_menu(self, id, item, window, event):
221 self.menubar.dispatch(id, item, window, event)
222
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000223
224 def do_unknownpartcode(self, partcode, window, event):
225 (what, message, when, where, modifiers) = event
Jack Jansen7a583361995-08-14 12:39:54 +0000226 if DEBUG: print "Mouse down at global:", where
227 if DEBUG: print "\tUnknown part code:", partcode
Jack Jansen7e0da901995-08-17 14:18:20 +0000228 if DEBUG: print "\tEvent:", self.printevent(event)
229 MacOS.HandleEvent(event)
230
231 def do_unknownwindow(self, partcode, window, event):
232 if DEBUG: print 'Unknown window:', window
Jack Jansen7a583361995-08-14 12:39:54 +0000233 MacOS.HandleEvent(event)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000234
235 def do_keyDown(self, event):
236 self.do_key(event)
237
238 def do_autoKey(self, event):
239 if not event[-1] & cmdKey:
240 self.do_key(event)
241
242 def do_key(self, event):
243 (what, message, when, where, modifiers) = event
244 c = chr(message & charCodeMask)
245 if modifiers & cmdKey:
246 if c == '.':
247 raise self
248 else:
249 result = MenuKey(ord(c))
250 id = (result>>16) & 0xffff # Hi word
251 item = result & 0xffff # Lo word
252 if id:
253 self.do_rawmenu(id, item, None, event)
Jack Jansen7e0da901995-08-17 14:18:20 +0000254# elif c == 'w':
255# w = FrontWindow()
256# if w:
257# self.do_close(w)
258# else:
259# if DEBUG: print 'Command-W without front window'
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000260 else:
Jack Jansen7a583361995-08-14 12:39:54 +0000261 if DEBUG: print "Command-" +`c`
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000262 else:
Jack Jansen7e0da901995-08-17 14:18:20 +0000263 # See whether the front window wants it
264 w = FrontWindow()
265 if w and self._windows.has_key(w):
266 window = self._windows[w]
267 try:
268 do_char = window.do_char
269 except AttributeError:
270 do_char = self.do_char
Jack Jansen6f47bf41995-12-12 15:03:35 +0000271 do_char(c, event)
272 # else it wasn't for us, sigh...
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000273
274 def do_char(self, c, event):
Jack Jansen7a583361995-08-14 12:39:54 +0000275 if DEBUG: print "Character", `c`
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000276
277 def do_updateEvt(self, event):
Jack Jansen7e0da901995-08-17 14:18:20 +0000278 (what, message, when, where, modifiers) = event
279 wid = WhichWindow(message)
280 if wid and self._windows.has_key(wid):
281 window = self._windows[wid]
282 window.do_rawupdate(wid, event)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000283 else:
Jack Jansen7a583361995-08-14 12:39:54 +0000284 MacOS.HandleEvent(event)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000285
Jack Jansen7e0da901995-08-17 14:18:20 +0000286 def do_activateEvt(self, event):
287 (what, message, when, where, modifiers) = event
Jack Jansenc8a99491996-01-08 23:50:13 +0000288 # XXXX Incorrect, should be fixed in suspendresume
289 if type(message) == type(1):
290 wid = WhichWindow(message)
291 else:
292 wid = message
Jack Jansen7e0da901995-08-17 14:18:20 +0000293 if wid and self._windows.has_key(wid):
294 window = self._windows[wid]
295 window.do_activate(modifiers & 1, event)
296 else:
297 MacOS.HandleEvent(event)
298
299 def do_osEvt(self, event):
300 (what, message, when, where, modifiers) = event
301 which = (message >> 24) & 0xff
302 if which == 1: # suspend/resume
303 self.do_suspendresume(event)
304 else:
305 if DEBUG:
306 print 'unknown osEvt:',
307 self.printevent(event)
308
309 def do_suspendresume(self, event):
310 # Is this a good idea???
311 (what, message, when, where, modifiers) = event
312 w = FrontWindow()
313 if w:
Jack Jansenc8a99491996-01-08 23:50:13 +0000314 # XXXX Incorrect, should stuff windowptr into message field
Jack Jansen7e0da901995-08-17 14:18:20 +0000315 nev = (activateEvt, w, when, where, message&1)
Jack Jansenc8a99491996-01-08 23:50:13 +0000316 self.do_activateEvt(nev)
Jack Jansen7e0da901995-08-17 14:18:20 +0000317
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000318 def do_kHighLevelEvent(self, event):
319 (what, message, when, where, modifiers) = event
Jack Jansen7a583361995-08-14 12:39:54 +0000320 if DEBUG:
321 print "High Level Event:",
322 self.printevent(event)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000323 try:
324 AEProcessAppleEvent(event)
325 except:
326 print "AEProcessAppleEvent error:"
327 traceback.print_exc()
328
329 def do_unknownevent(self, event):
Jack Jansen7e0da901995-08-17 14:18:20 +0000330 if DEBUG:
331 print "Unhandled event:",
332 self.printevent(event)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000333
334 def printevent(self, event):
335 (what, message, when, where, modifiers) = event
336 nicewhat = `what`
337 if eventname.has_key(what):
338 nicewhat = eventname[what]
339 print nicewhat,
340 if what == kHighLevelEvent:
341 h, v = where
342 print `ostypecode(message)`, hex(when), `ostypecode(h | (v<<16))`,
343 else:
344 print hex(message), hex(when), where,
345 print hex(modifiers)
346
347
348class MenuBar:
349 """Represent a set of menus in a menu bar.
350
351 Interface:
352
353 - (constructor)
354 - (destructor)
355 - addmenu
356 - addpopup (normally used internally)
357 - dispatch (called from Application)
358 """
359
360 nextid = 1 # Necessarily a class variable
361
362 def getnextid(self):
363 id = self.nextid
364 self.nextid = id+1
365 return id
366
367 def __init__(self):
368 ClearMenuBar()
369 self.bar = GetMenuBar()
370 self.menus = {}
371
372 def addmenu(self, title, after = 0):
373 id = self.getnextid()
374 m = NewMenu(id, title)
375 m.InsertMenu(after)
376 DrawMenuBar()
377 return id, m
378
379 def addpopup(self, title = ''):
380 return self.addmenu(title, -1)
381
382 def install(self):
383 self.bar.SetMenuBar()
384 DrawMenuBar()
385
386 def dispatch(self, id, item, window, event):
387 if self.menus.has_key(id):
388 self.menus[id].dispatch(id, item, window, event)
389 else:
Jack Jansen7a583361995-08-14 12:39:54 +0000390 if DEBUG: print "MenuBar.dispatch(%d, %d, %s, %s)" % \
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000391 (id, item, window, event)
392
393
394# XXX Need a way to get menus as resources and bind them to callbacks
395
396class Menu:
397 "One menu."
398
399 def __init__(self, bar, title, after=0):
400 self.bar = bar
401 self.id, self.menu = self.bar.addmenu(title, after)
402 bar.menus[self.id] = self
403 self.items = []
404
405 def additem(self, label, shortcut=None, callback=None, kind=None):
406 self.menu.AppendMenu('x') # add a dummy string
407 self.items.append(label, shortcut, callback, kind)
408 item = len(self.items)
Jack Jansene4b40381995-07-17 13:25:15 +0000409 self.menu.SetMenuItemText(item, label) # set the actual text
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000410 if shortcut:
411 self.menu.SetItemCmd(item, ord(shortcut))
412 return item
413
414 def addcheck(self, label, shortcut=None, callback=None):
415 return self.additem(label, shortcut, callback, 'check')
416
417 def addradio(self, label, shortcut=None, callback=None):
418 return self.additem(label, shortcut, callback, 'radio')
419
420 def addseparator(self):
421 self.menu.AppendMenu('(-')
422 self.items.append('', None, None, 'separator')
423
424 def addsubmenu(self, label, title=''):
425 sub = Menu(self.bar, title, -1)
426 item = self.additem(label, '\x1B', None, 'submenu')
427 self.menu.SetItemMark(item, sub.id)
428 return sub
429
430 def dispatch(self, id, item, window, event):
431 title, shortcut, callback, type = self.items[item-1]
432 if callback:
433 callback(id, item, window, event)
434
435
436class MenuItem:
437 def __init__(self, menu, title, shortcut=None, callback=None, kind=None):
438 self.item = menu.additem(title, shortcut, callback)
439
440class RadioItem(MenuItem):
441 def __init__(self, menu, title, shortcut=None, callback=None):
442 MenuItem.__init__(self, menu, title, shortcut, callback, 'radio')
443
444class CheckItem(MenuItem):
445 def __init__(self, menu, title, shortcut=None, callback=None):
446 MenuItem.__init__(self, menu, title, shortcut, callback, 'check')
447
448def Separator(menu):
449 menu.addseparator()
450
451def SubMenu(menu, label, title=''):
452 return menu.addsubmenu(label, title)
453
454
455class AppleMenu(Menu):
456
457 def __init__(self, bar, abouttext="About me...", aboutcallback=None):
458 Menu.__init__(self, bar, "\024")
459 self.additem(abouttext, None, aboutcallback)
460 self.addseparator()
Jack Jansene4b40381995-07-17 13:25:15 +0000461 self.menu.AppendResMenu('DRVR')
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000462
463 def dispatch(self, id, item, window, event):
464 if item == 1:
465 Menu.dispatch(self, id, item, window, event)
466 else:
Jack Jansenc8a99491996-01-08 23:50:13 +0000467 name = self.menu.GetMenuItemText(item)
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000468 OpenDeskAcc(name)
469
Jack Jansen7e0da901995-08-17 14:18:20 +0000470class Window:
471 """A single window belonging to an application"""
472
473 def __init__(self, parent):
474 self.wid = None
475 self.parent = parent
476
Jack Jansenc8a99491996-01-08 23:50:13 +0000477 def open(self, bounds=(40, 40, 400, 400), resid=None):
478 if resid <> None:
479 self.wid = GetNewWindow(resid, -1)
480 else:
481 self.wid = NewWindow(bounds, self.__class__.__name__, 1,
Jack Jansen7e0da901995-08-17 14:18:20 +0000482 0, -1, 1, 0)
483 self.do_postopen()
484
485 def do_postopen(self):
486 """Tell our parent we exist"""
487 self.parent.appendwindow(self.wid, self)
488
489 def close(self):
Jack Jansen7e0da901995-08-17 14:18:20 +0000490 self.do_postclose()
491
492 def do_postclose(self):
493 self.parent.removewindow(self.wid)
494 self.parent = None
495 self.wid = None
Jack Jansenc8a99491996-01-08 23:50:13 +0000496
497 def SetPort(self):
498 # Convinience method
499 SetPort(self.wid)
Jack Jansen7e0da901995-08-17 14:18:20 +0000500
501 def do_inDrag(self, partcode, window, event):
502 where = event[3]
503 window.DragWindow(where, self.draglimit)
504
505 draglimit = everywhere
506
507 def do_inGoAway(self, partcode, window, event):
508 where = event[3]
509 if window.TrackGoAway(where):
510 self.close()
511
512 def do_inZoom(self, partcode, window, event):
513 (what, message, when, where, modifiers) = event
514 if window.TrackBox(where, partcode):
515 window.ZoomWindow(partcode, 1)
516
517 def do_inZoomIn(self, partcode, window, event):
518 SetPort(window) # !!!
519 self.do_inZoom(partcode, window, event)
520
521 def do_inZoomOut(self, partcode, window, event):
522 SetPort(window) # !!!
523 self.do_inZoom(partcode, window, event)
524
525 def do_inGrow(self, partcode, window, event):
526 (what, message, when, where, modifiers) = event
527 result = window.GrowWindow(where, self.growlimit)
528 if result:
529 height = (result>>16) & 0xffff # Hi word
530 width = result & 0xffff # Lo word
531 self.do_resize(width, height, window)
532
533 growlimit = everywhere
534
535 def do_resize(self, width, height, window):
536 window.SizeWindow(width, height, 0)
537 self.do_postresize(width, height, window)
538
539 def do_postresize(self, width, height, window):
540 SetPort(window)
541 InvalRect(everywhere)
542
543 def do_inContent(self, partcode, window, event):
544 #
545 # If we're not frontmost, select ourselves and wait for
546 # the activate event.
547 #
548 if FrontWindow() <> window:
549 window.SelectWindow()
550 return
551 # We are. Handle the event.
552 (what, message, when, where, modifiers) = event
553 SetPort(window)
554 local = GlobalToLocal(where)
555 self.do_contentclick(local, modifiers, event)
556
557 def do_contentclick(self, local, modifiers, event):
558 print 'Click in contents at %s, modifiers %s'%(local, modifiers)
559
560 def do_rawupdate(self, window, event):
561 if DEBUG: print "raw update for", window
Jack Jansenda38f2d1995-11-14 10:15:42 +0000562 SetPort(window)
Jack Jansen7e0da901995-08-17 14:18:20 +0000563 window.BeginUpdate()
564 self.do_update(window, event)
565 window.EndUpdate()
566
567 def do_update(self, window, event):
568 EraseRect(everywhere)
569
570 def do_activate(self, activate, event):
571 if DEBUG: print 'Activate %d for %s'%(activate, self.wid)
572
573class ControlsWindow(Window):
574
575 def do_rawupdate(self, window, event):
576 if DEBUG: print "raw update for", window
577 window.BeginUpdate()
578 self.do_update(window, event)
579 DrawControls(window)
580 window.DrawGrowIcon()
581 window.EndUpdate()
582
583 def do_controlhit(self, window, control, pcode, event):
584 if DEBUG: print "control hit in", window, "on", control, "; pcode =", pcode
585
586 def do_inContent(self, partcode, window, event):
587 (what, message, when, where, modifiers) = event
Jack Jansenda38f2d1995-11-14 10:15:42 +0000588 SetPort(window) # XXXX Needed?
Jack Jansen7e0da901995-08-17 14:18:20 +0000589 local = GlobalToLocal(where)
590 ctltype, control = FindControl(local, window)
591 if ctltype and control:
592 pcode = control.TrackControl(local)
593 if pcode:
594 self.do_controlhit(window, control, pcode, event)
595 else:
596 if DEBUG: print "FindControl(%s, %s) -> (%s, %s)" % \
597 (local, window, ctltype, control)
598
599class DialogWindow(Window):
600 """A modeless dialog window"""
601
602 def open(self, resid):
603 self.wid = GetNewDialog(resid, -1)
604 self.do_postopen()
605
606 def close(self):
Jack Jansen7e0da901995-08-17 14:18:20 +0000607 self.do_postclose()
608
609 def do_itemhit(self, item, event):
610 print 'Dialog %s, item %d hit'%(self.wid, item)
611
612 def do_rawupdate(self, window, event):
613 pass
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000614
615def ostypecode(x):
616 "Convert a long int to the 4-character code it really is"
617 s = ''
618 for i in range(4):
619 x, c = divmod(x, 256)
620 s = chr(c) + s
621 return s
622
623
624class TestApp(Application):
625
626 "This class is used by the test() function"
627
628 def makeusermenus(self):
629 self.filemenu = m = Menu(self.menubar, "File")
630 self.saveitem = MenuItem(m, "Save", "S", self.save)
631 Separator(m)
632 self.optionsmenu = mm = SubMenu(m, "Options")
633 self.opt1 = CheckItem(mm, "Arguments")
634 self.opt2 = CheckItem(mm, "Being hit on the head lessons")
635 self.opt3 = CheckItem(mm, "Complaints")
636 Separator(m)
637 self.quititem = MenuItem(m, "Quit", "Q", self.quit)
638
639 def save(self, *args):
640 print "Save"
641
642 def quit(self, *args):
643 raise self
644
645
646def test():
647 "Test program"
648 app = TestApp()
649 app.mainloop()
650
651
652if __name__ == '__main__':
653 test()