blob: d1592ed56e2ad2f0cdd42829ef1b655644644fcd [file] [log] [blame]
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +00001"A sort of application framework for the Mac"
2
3
4import MacOS
5import traceback
6
7from addpack import addpack
Jack Jansene4b40381995-07-17 13:25:15 +00008addpack('Tools')
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +00009addpack('bgen')
10addpack('ae')
11#addpack('ctl')
12addpack('dlg')
13addpack('evt')
14addpack('menu')
15#addpack('qd')
16#addpack('res')
17#addpack('snd')
18addpack('win')
19
20from AE import *
21from AppleEvents import *
22#from Ctl import *
23#from Controls import *
24from Dlg import *
25from Dialogs import *
26from Evt import *
27from Events import *
28from Menu import *
29from Menus import *
30#from Qd import *
31#from QuickDraw import *
32#from Res import *
33#from Resources import *
34#from Snd import *
35#from Sound import *
36from Win import *
37from Windows import *
38
39import EasyDialogs
40
41kHighLevelEvent = 23 # Don't know what header file this should come from
42
43
44# Map event 'what' field to strings
45eventname = {}
46eventname[1] = 'mouseDown'
47eventname[2] = 'mouseUp'
48eventname[3] = 'keyDown'
49eventname[4] = 'keyUp'
50eventname[5] = 'autoKey'
51eventname[6] = 'updateEvt'
52eventname[7] = 'diskEvt'
53eventname[8] = 'activateEvt'
54eventname[15] = 'osEvt'
55eventname[23] = 'kHighLevelEvent'
56
57# Map part codes returned by WhichWindow() to strings
58partname = {}
59partname[0] = 'inDesk'
60partname[1] = 'inMenuBar'
61partname[2] = 'inSysWindow'
62partname[3] = 'inContent'
63partname[4] = 'inDrag'
64partname[5] = 'inGrow'
65partname[6] = 'inGoAway'
66partname[7] = 'inZoomIn'
67partname[8] = 'inZoomOut'
68
69# A rectangle that's bigger than the screen,
70# but not so big that adding the screen size to it will cause 16-bit overflow
71everywhere = (-16000, -16000, 16000, 16000)
72
73
74class Application:
75
76 "Application framework -- your application should be a derived class"
77
78 def __init__(self):
79 self.makemenubar()
80
81 def makemenubar(self):
82 self.menubar = MenuBar()
83 AppleMenu(self.menubar, self.getabouttext(), self.do_about)
84 self.makeusermenus()
85
86 def getabouttext(self):
87 return "About %s..." % self.__class__.__name__
88
89 def do_about(self, id, item, window, event):
90 EasyDialogs.Message("Hello, world!" + "\015(%s)" % self.__class__.__name__)
91
92 # The main event loop is broken up in several simple steps.
93 # This is done so you can override each individual part,
94 # if you have a need to do extra processing independent of the
95 # event type.
96 # Normally, however, you'd just define handlers for individual
97 # events.
98 # (XXX I'm not sure if using default parameter values is the right
99 # way to define the mask and wait time passed to WaitNextEvent.)
100
101 def mainloop(self, mask = everyEvent, wait = 0):
102 saveyield = MacOS.EnableAppswitch(self.yield)
103 try:
104 while 1:
105 try:
106 self.do1event(mask, wait)
107 except (Application, SystemExit):
108 break
109 finally:
110 MacOS.EnableAppswitch(saveyield)
111
112 yield = -1
113
114 def do1event(self, mask = everyEvent, wait = 0):
115 event = self.getevent(mask, wait)
116 if event:
117 self.dispatch(event)
118
119 def getevent(self, mask = everyEvent, wait = 0):
120 ok, event = WaitNextEvent(mask, wait)
121 if ok:
122 return event
123 else:
124 return None
125
126 def dispatch(self, event):
127 (what, message, when, where, modifiers) = event
128 if eventname.has_key(what):
129 name = "do_" + eventname[what]
130 else:
131 name = "do_%d" % what
132 try:
133 handler = getattr(self, name)
134 except AttributeError:
135 handler = self.do_unknownevent
136 handler(event)
137
138 def do_mouseDown(self, event):
139 (what, message, when, where, modifiers) = event
140 partcode, window = FindWindow(where)
141 if partname.has_key(partcode):
142 name = "do_" + partname[partcode]
143 else:
144 name = "do_%d" % partcode
145 try:
146 handler = getattr(self, name)
147 except AttrinuteError:
148 handler = self.do_unknownpartcode
149 handler(partcode, window, event)
150
151 def do_inDrag(self, partcode, window, event):
152 window.DragWindow(where, self.draglimit)
153
154 draglimit = everywhere
155
156 def do_inGoAway(self, partcode, window, event):
157 if window.TrackGoAway(where):
158 self.do_close(window)
159
160 def do_close(self, window):
161 print "Should close window:", window
162
163 def do_inZoom(self, partcode, window, event):
164 (what, message, when, where, modifiers) = event
165 if window.TrackBox(where, partcode):
166 window.ZoomWindow(partcode, 1)
167
168 def do_inZoomIn(self, partcode, window, event):
169 SetPort(window) # !!!
170 self.do_inZoom(partcode, window, event)
171
172 def do_inZoomOut(self, partcode, window, event):
173 SetPort(window) # !!!
174 self.do_inZoom(partcode, window, event)
175
176 def do_inSysWindow(self, partcode, window, event):
177 print "SystemClick", event, window
178 # SystemClick(event, window) # XXX useless, window is None
179
180 def do_inDesk(self, partcode, window, event):
181 print "inDesk"
182 # XXX what to do with it?
183
184 def do_inMenuBar(self, partcode, window, event):
185 (what, message, when, where, modifiers) = event
186 result = MenuSelect(where)
187 id = (result>>16) & 0xffff # Hi word
188 item = result & 0xffff # Lo word
189 self.do_rawmenu(id, item, window, event)
190
191 def do_rawmenu(self, id, item, window, event):
192 try:
193 self.do_menu(id, item, window, event)
194 finally:
195 HiliteMenu(0)
196
197 def do_menu(self, id, item, window, event):
198 self.menubar.dispatch(id, item, window, event)
199
200 def do_inGrow(self, partcode, window, event):
201 (what, message, when, where, modifiers) = event
202 result = window.GrowWindow(where, self.growlimit)
203 if result:
204 height = (result>>16) & 0xffff # Hi word
205 width = result & 0xffff # Lo word
206 self.do_resize(width, height, window)
207
208 growlimit = everywhere
209
210 def do_resize(self, width, height, window):
211 window.SizeWindow(width, height, 0)
212 self.do_postresize(width, height, window)
213
214 def do_postresize(self, width, height, window):
215 SetPort(window)
216 InvalRect(everywhere)
217
218 def do_inContent(self, partcode, window, event):
219 (what, message, when, where, modifiers) = event
220 local = GlobalToLocal(where)
221 ctltype, control = FindControl(local, window)
222 if ctltype and control:
223 pcode = control.TrackControl(local)
224 if pcode:
225 self.do_controlhit(window, control, pcode, event)
226 else:
227 print "FindControl(%s, %s) -> (%s, %s)" % \
228 (local, window, ctltype, control)
229
230 def do_controlhit(self, window, control, pcode, event):
231 print "control hit in", window, "on", control, "; pcode =", pcode
232
233 def do_unknownpartcode(self, partcode, window, event):
234 (what, message, when, where, modifiers) = event
235 print "Mouse down at global:", where
236 print "\tUnknown part code:", partcode
237
238 def do_keyDown(self, event):
239 self.do_key(event)
240
241 def do_autoKey(self, event):
242 if not event[-1] & cmdKey:
243 self.do_key(event)
244
245 def do_key(self, event):
246 (what, message, when, where, modifiers) = event
247 c = chr(message & charCodeMask)
248 if modifiers & cmdKey:
249 if c == '.':
250 raise self
251 else:
252 result = MenuKey(ord(c))
253 id = (result>>16) & 0xffff # Hi word
254 item = result & 0xffff # Lo word
255 if id:
256 self.do_rawmenu(id, item, None, event)
257 elif c == 'w':
258 w = FrontWindow()
259 if w:
260 self.do_close(w)
261 else:
262 print 'Command-W without front window'
263 else:
264 print "Command-" +`c`
265 else:
266 self.do_char(c, event)
267
268 def do_char(self, c, event):
269 print "Character", `c`
270
271 def do_updateEvt(self, event):
272 print "do_update",
273 self.printevent(event)
274 window = FrontWindow() # XXX This is wrong!
275 if window:
276 self.do_rawupdate(window, event)
277 else:
278 print "no window for do_updateEvt"
279
280 def do_rawupdate(self, window, event):
281 print "raw update for", window
282 window.BeginUpdate()
283 self.do_update(window, event)
284 DrawControls(window)
285 window.DrawGrowIcon()
286 window.EndUpdate()
287
288 def do_update(self, window, event):
289 EraseRect(everywhere)
290
291 def do_kHighLevelEvent(self, event):
292 (what, message, when, where, modifiers) = event
293 print "High Level Event:",
294 self.printevent(event)
295 try:
296 AEProcessAppleEvent(event)
297 except:
298 print "AEProcessAppleEvent error:"
299 traceback.print_exc()
300
301 def do_unknownevent(self, event):
302 print "Unknown event:",
303 self.printevent(event)
304
305 def printevent(self, event):
306 (what, message, when, where, modifiers) = event
307 nicewhat = `what`
308 if eventname.has_key(what):
309 nicewhat = eventname[what]
310 print nicewhat,
311 if what == kHighLevelEvent:
312 h, v = where
313 print `ostypecode(message)`, hex(when), `ostypecode(h | (v<<16))`,
314 else:
315 print hex(message), hex(when), where,
316 print hex(modifiers)
317
318
319class MenuBar:
320 """Represent a set of menus in a menu bar.
321
322 Interface:
323
324 - (constructor)
325 - (destructor)
326 - addmenu
327 - addpopup (normally used internally)
328 - dispatch (called from Application)
329 """
330
331 nextid = 1 # Necessarily a class variable
332
333 def getnextid(self):
334 id = self.nextid
335 self.nextid = id+1
336 return id
337
338 def __init__(self):
339 ClearMenuBar()
340 self.bar = GetMenuBar()
341 self.menus = {}
342
343 def addmenu(self, title, after = 0):
344 id = self.getnextid()
345 m = NewMenu(id, title)
346 m.InsertMenu(after)
347 DrawMenuBar()
348 return id, m
349
350 def addpopup(self, title = ''):
351 return self.addmenu(title, -1)
352
353 def install(self):
354 self.bar.SetMenuBar()
355 DrawMenuBar()
356
357 def dispatch(self, id, item, window, event):
358 if self.menus.has_key(id):
359 self.menus[id].dispatch(id, item, window, event)
360 else:
361 print "MenuBar.dispatch(%d, %d, %s, %s)" % \
362 (id, item, window, event)
363
364
365# XXX Need a way to get menus as resources and bind them to callbacks
366
367class Menu:
368 "One menu."
369
370 def __init__(self, bar, title, after=0):
371 self.bar = bar
372 self.id, self.menu = self.bar.addmenu(title, after)
373 bar.menus[self.id] = self
374 self.items = []
375
376 def additem(self, label, shortcut=None, callback=None, kind=None):
377 self.menu.AppendMenu('x') # add a dummy string
378 self.items.append(label, shortcut, callback, kind)
379 item = len(self.items)
Jack Jansene4b40381995-07-17 13:25:15 +0000380 self.menu.SetMenuItemText(item, label) # set the actual text
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000381 if shortcut:
382 self.menu.SetItemCmd(item, ord(shortcut))
383 return item
384
385 def addcheck(self, label, shortcut=None, callback=None):
386 return self.additem(label, shortcut, callback, 'check')
387
388 def addradio(self, label, shortcut=None, callback=None):
389 return self.additem(label, shortcut, callback, 'radio')
390
391 def addseparator(self):
392 self.menu.AppendMenu('(-')
393 self.items.append('', None, None, 'separator')
394
395 def addsubmenu(self, label, title=''):
396 sub = Menu(self.bar, title, -1)
397 item = self.additem(label, '\x1B', None, 'submenu')
398 self.menu.SetItemMark(item, sub.id)
399 return sub
400
401 def dispatch(self, id, item, window, event):
402 title, shortcut, callback, type = self.items[item-1]
403 if callback:
404 callback(id, item, window, event)
405
406
407class MenuItem:
408 def __init__(self, menu, title, shortcut=None, callback=None, kind=None):
409 self.item = menu.additem(title, shortcut, callback)
410
411class RadioItem(MenuItem):
412 def __init__(self, menu, title, shortcut=None, callback=None):
413 MenuItem.__init__(self, menu, title, shortcut, callback, 'radio')
414
415class CheckItem(MenuItem):
416 def __init__(self, menu, title, shortcut=None, callback=None):
417 MenuItem.__init__(self, menu, title, shortcut, callback, 'check')
418
419def Separator(menu):
420 menu.addseparator()
421
422def SubMenu(menu, label, title=''):
423 return menu.addsubmenu(label, title)
424
425
426class AppleMenu(Menu):
427
428 def __init__(self, bar, abouttext="About me...", aboutcallback=None):
429 Menu.__init__(self, bar, "\024")
430 self.additem(abouttext, None, aboutcallback)
431 self.addseparator()
Jack Jansene4b40381995-07-17 13:25:15 +0000432 self.menu.AppendResMenu('DRVR')
Guido van Rossum8f4b6ad1995-04-05 09:18:35 +0000433
434 def dispatch(self, id, item, window, event):
435 if item == 1:
436 Menu.dispatch(self, id, item, window, event)
437 else:
438 name = self.menu.GetItem(item)
439 OpenDeskAcc(name)
440
441
442def ostypecode(x):
443 "Convert a long int to the 4-character code it really is"
444 s = ''
445 for i in range(4):
446 x, c = divmod(x, 256)
447 s = chr(c) + s
448 return s
449
450
451class TestApp(Application):
452
453 "This class is used by the test() function"
454
455 def makeusermenus(self):
456 self.filemenu = m = Menu(self.menubar, "File")
457 self.saveitem = MenuItem(m, "Save", "S", self.save)
458 Separator(m)
459 self.optionsmenu = mm = SubMenu(m, "Options")
460 self.opt1 = CheckItem(mm, "Arguments")
461 self.opt2 = CheckItem(mm, "Being hit on the head lessons")
462 self.opt3 = CheckItem(mm, "Complaints")
463 Separator(m)
464 self.quititem = MenuItem(m, "Quit", "Q", self.quit)
465
466 def save(self, *args):
467 print "Save"
468
469 def quit(self, *args):
470 raise self
471
472
473def test():
474 "Test program"
475 app = TestApp()
476 app.mainloop()
477
478
479if __name__ == '__main__':
480 test()