1"A sort of application framework for the Mac" 2 3DEBUG=0 4 5from warnings import warnpy3k 6warnpy3k("In 3.x, the FrameWork module is removed.", stacklevel=2) 7 8import MacOS 9import traceback 10 11from Carbon.AE import * 12from Carbon.AppleEvents import * 13from Carbon.Ctl import * 14from Carbon.Controls import * 15from Carbon.Dlg import * 16from Carbon.Dialogs import * 17from Carbon.Evt import * 18from Carbon.Events import * 19from Carbon.Help import * 20from Carbon.Menu import * 21from Carbon.Menus import * 22from Carbon.Qd import * 23from Carbon.QuickDraw import * 24#from Carbon.Res import * 25#from Carbon.Resources import * 26#from Carbon.Snd import * 27#from Carbon.Sound import * 28from Carbon.Win import * 29from Carbon.Windows import * 30import types 31 32import EasyDialogs 33 34try: 35 MyFrontWindow = FrontNonFloatingWindow 36except NameError: 37 MyFrontWindow = FrontWindow 38 39kHighLevelEvent = 23 # Don't know what header file this should come from 40SCROLLBARWIDTH = 16 # Again, not a clue... 41 42# Trick to forestall a set of SIOUX menus being added to our menubar 43SIOUX_APPLEMENU_ID=32000 44 45 46# Map event 'what' field to strings 47eventname = {} 48eventname[1] = 'mouseDown' 49eventname[2] = 'mouseUp' 50eventname[3] = 'keyDown' 51eventname[4] = 'keyUp' 52eventname[5] = 'autoKey' 53eventname[6] = 'updateEvt' 54eventname[7] = 'diskEvt' 55eventname[8] = 'activateEvt' 56eventname[15] = 'osEvt' 57eventname[23] = 'kHighLevelEvent' 58 59# Map part codes returned by WhichWindow() to strings 60partname = {} 61partname[0] = 'inDesk' 62partname[1] = 'inMenuBar' 63partname[2] = 'inSysWindow' 64partname[3] = 'inContent' 65partname[4] = 'inDrag' 66partname[5] = 'inGrow' 67partname[6] = 'inGoAway' 68partname[7] = 'inZoomIn' 69partname[8] = 'inZoomOut' 70 71# 72# The useable portion of the screen 73# ## but what happens with multiple screens? jvr 74screenbounds = GetQDGlobalsScreenBits().bounds 75screenbounds = screenbounds[0]+4, screenbounds[1]+4, \ 76 screenbounds[2]-4, screenbounds[3]-4 77 78next_window_x = 16 # jvr 79next_window_y = 44 # jvr 80 81def windowbounds(width, height): 82 "Return sensible window bounds" 83 global next_window_x, next_window_y 84 r, b = next_window_x+width, next_window_y+height 85 if r > screenbounds[2]: 86 next_window_x = 16 87 if b > screenbounds[3]: 88 next_window_y = 44 89 l, t = next_window_x, next_window_y 90 r, b = next_window_x+width, next_window_y+height 91 next_window_x, next_window_y = next_window_x + 8, next_window_y + 20 # jvr 92 return l, t, r, b 93 94_watch = None 95def setwatchcursor(): 96 global _watch 97 98 if _watch is None: 99 _watch = GetCursor(4).data 100 SetCursor(_watch) 101 102def setarrowcursor(): 103 SetCursor(GetQDGlobalsArrow()) 104 105class Application: 106 107 "Application framework -- your application should be a derived class" 108 109 def __init__(self, nomenubar=0): 110 self._doing_asyncevents = 0 111 self.quitting = 0 112 self.needmenubarredraw = 0 113 self._windows = {} 114 self._helpmenu = None 115 if nomenubar: 116 self.menubar = None 117 else: 118 self.makemenubar() 119 120 def __del__(self): 121 if self._doing_asyncevents: 122 self._doing_asyncevents = 0 123 MacOS.SetEventHandler() 124 125 def makemenubar(self): 126 self.menubar = MenuBar(self) 127 AppleMenu(self.menubar, self.getabouttext(), self.do_about) 128 self.makeusermenus() 129 130 def makeusermenus(self): 131 self.filemenu = m = Menu(self.menubar, "File") 132 self._quititem = MenuItem(m, "Quit", "Q", self._quit) 133 134 def gethelpmenu(self): 135 if self._helpmenu is None: 136 self._helpmenu = HelpMenu(self.menubar) 137 return self._helpmenu 138 139 def _quit(self, *args): 140 self.quitting = 1 141 142 def cleanup(self): 143 for w in self._windows.values(): 144 w.do_close() 145 return self._windows == {} 146 147 def appendwindow(self, wid, window): 148 self._windows[wid] = window 149 150 def removewindow(self, wid): 151 del self._windows[wid] 152 153 def getabouttext(self): 154 return "About %s..." % self.__class__.__name__ 155 156 def do_about(self, id, item, window, event): 157 EasyDialogs.Message("Hello, world!" + "\015(%s)" % self.__class__.__name__) 158 159 # The main event loop is broken up in several simple steps. 160 # This is done so you can override each individual part, 161 # if you have a need to do extra processing independent of the 162 # event type. 163 # Normally, however, you'd just define handlers for individual 164 # events. 165 166 schedparams = (0, 0) # By default disable Python's event handling 167 default_wait = None # By default we wait GetCaretTime in WaitNextEvent 168 169 def mainloop(self, mask = everyEvent, wait = None): 170 self.quitting = 0 171 if hasattr(MacOS, 'SchedParams'): 172 saveparams = MacOS.SchedParams(*self.schedparams) 173 try: 174 while not self.quitting: 175 try: 176 self.do1event(mask, wait) 177 except (Application, SystemExit): 178 # Note: the raising of "self" is old-fashioned idiom to 179 # exit the mainloop. Calling _quit() is better for new 180 # applications. 181 break 182 finally: 183 if hasattr(MacOS, 'SchedParams'): 184 MacOS.SchedParams(*saveparams) 185 186 def dopendingevents(self, mask = everyEvent): 187 """dopendingevents - Handle all pending events""" 188 while self.do1event(mask, wait=0): 189 pass 190 191 def do1event(self, mask = everyEvent, wait = None): 192 ok, event = self.getevent(mask, wait) 193 if IsDialogEvent(event): 194 if self.do_dialogevent(event): 195 return 196 if ok: 197 self.dispatch(event) 198 else: 199 self.idle(event) 200 201 def idle(self, event): 202 pass 203 204 def getevent(self, mask = everyEvent, wait = None): 205 if self.needmenubarredraw: 206 DrawMenuBar() 207 self.needmenubarredraw = 0 208 if wait is None: 209 wait = self.default_wait 210 if wait is None: 211 wait = GetCaretTime() 212 ok, event = WaitNextEvent(mask, wait) 213 return ok, event 214 215 def dispatch(self, event): 216 # The following appears to be double work (already done in do1event) 217 # but we need it for asynchronous event handling 218 if IsDialogEvent(event): 219 if self.do_dialogevent(event): 220 return 221 (what, message, when, where, modifiers) = event 222 if what in eventname: 223 name = "do_" + eventname[what] 224 else: 225 name = "do_%d" % what 226 try: 227 handler = getattr(self, name) 228 except AttributeError: 229 handler = self.do_unknownevent 230 handler(event) 231 232 def asyncevents(self, onoff): 233 """asyncevents - Set asynchronous event handling on or off""" 234 if MacOS.runtimemodel == 'macho': 235 raise 'Unsupported in MachoPython' 236 old = self._doing_asyncevents 237 if old: 238 MacOS.SetEventHandler() 239 MacOS.SchedParams(*self.schedparams) 240 if onoff: 241 MacOS.SetEventHandler(self.dispatch) 242 doint, dummymask, benice, howoften, bgyield = \ 243 self.schedparams 244 MacOS.SchedParams(doint, everyEvent, benice, 245 howoften, bgyield) 246 self._doing_asyncevents = onoff 247 return old 248 249 def do_dialogevent(self, event): 250 gotone, dlg, item = DialogSelect(event) 251 if gotone: 252 window = dlg.GetDialogWindow() 253 if window in self._windows: 254 self._windows[window].do_itemhit(item, event) 255 else: 256 print 'Dialog event for unknown dialog' 257 return 1 258 return 0 259 260 def do_mouseDown(self, event): 261 (what, message, when, where, modifiers) = event 262 partcode, wid = FindWindow(where) 263 264 # 265 # Find the correct name. 266 # 267 if partcode in partname: 268 name = "do_" + partname[partcode] 269 else: 270 name = "do_%d" % partcode 271 272 if wid is None: 273 # No window, or a non-python window 274 try: 275 handler = getattr(self, name) 276 except AttributeError: 277 # Not menubar or something, so assume someone 278 # else's window 279 if hasattr(MacOS, 'HandleEvent'): 280 MacOS.HandleEvent(event) 281 return 282 elif wid in self._windows: 283 # It is a window. Hand off to correct window. 284 window = self._windows[wid] 285 try: 286 handler = getattr(window, name) 287 except AttributeError: 288 handler = self.do_unknownpartcode 289 else: 290 # It is a python-toolbox window, but not ours. 291 handler = self.do_unknownwindow 292 handler(partcode, wid, event) 293 294 def do_inSysWindow(self, partcode, window, event): 295 if hasattr(MacOS, 'HandleEvent'): 296 MacOS.HandleEvent(event) 297 298 def do_inDesk(self, partcode, window, event): 299 if hasattr(MacOS, 'HandleEvent'): 300 MacOS.HandleEvent(event) 301 302 def do_inMenuBar(self, partcode, window, event): 303 if not self.menubar: 304 if hasattr(MacOS, 'HandleEvent'): 305 MacOS.HandleEvent(event) 306 return 307 (what, message, when, where, modifiers) = event 308 result = MenuSelect(where) 309 id = (result>>16) & 0xffff # Hi word 310 if id >= 0x8000: 311 id = -65536 + id 312 item = result & 0xffff # Lo word 313 self.do_rawmenu(id, item, window, event) 314 315 def do_rawmenu(self, id, item, window, event): 316 try: 317 self.do_menu(id, item, window, event) 318 finally: 319 HiliteMenu(0) 320 321 def do_menu(self, id, item, window, event): 322 if hasattr(MacOS, 'OutputSeen'): 323 MacOS.OutputSeen() 324 self.menubar.dispatch(id, item, window, event) 325 326 327 def do_unknownpartcode(self, partcode, window, event): 328 (what, message, when, where, modifiers) = event 329 if DEBUG: print "Mouse down at global:", where 330 if DEBUG: print "\tUnknown part code:", partcode 331 if DEBUG: print "\tEvent:", self.printevent(event) 332 if hasattr(MacOS, 'HandleEvent'): 333 MacOS.HandleEvent(event) 334 335 def do_unknownwindow(self, partcode, window, event): 336 if DEBUG: print 'Unknown window:', window 337 if hasattr(MacOS, 'HandleEvent'): 338 MacOS.HandleEvent(event) 339 340 def do_keyDown(self, event): 341 self.do_key(event) 342 343 def do_autoKey(self, event): 344 if not event[-1] & cmdKey: 345 self.do_key(event) 346 347 def do_key(self, event): 348 (what, message, when, where, modifiers) = event 349 c = chr(message & charCodeMask) 350 if self.menubar: 351 result = MenuEvent(event) 352 id = (result>>16) & 0xffff # Hi word 353 item = result & 0xffff # Lo word 354 if id: 355 self.do_rawmenu(id, item, None, event) 356 return 357 # Otherwise we fall-through 358 if modifiers & cmdKey: 359 if c == '.': 360 raise self 361 else: 362 if not self.menubar: 363 if hasattr(MacOS, 'HandleEvent'): 364 MacOS.HandleEvent(event) 365 return 366 else: 367 # See whether the front window wants it 368 w = MyFrontWindow() 369 if w and w in self._windows: 370 window = self._windows[w] 371 try: 372 do_char = window.do_char 373 except AttributeError: 374 do_char = self.do_char 375 do_char(c, event) 376 # else it wasn't for us, sigh... 377 378 def do_char(self, c, event): 379 if DEBUG: print "Character", repr(c) 380 381 def do_updateEvt(self, event): 382 (what, message, when, where, modifiers) = event 383 wid = WhichWindow(message) 384 if wid and wid in self._windows: 385 window = self._windows[wid] 386 window.do_rawupdate(wid, event) 387 else: 388 if hasattr(MacOS, 'HandleEvent'): 389 MacOS.HandleEvent(event) 390 391 def do_activateEvt(self, event): 392 (what, message, when, where, modifiers) = event 393 wid = WhichWindow(message) 394 if wid and wid in self._windows: 395 window = self._windows[wid] 396 window.do_activate(modifiers & 1, event) 397 else: 398 if hasattr(MacOS, 'HandleEvent'): 399 MacOS.HandleEvent(event) 400 401 def do_osEvt(self, event): 402 (what, message, when, where, modifiers) = event 403 which = (message >> 24) & 0xff 404 if which == 1: # suspend/resume 405 self.do_suspendresume(event) 406 else: 407 if DEBUG: 408 print 'unknown osEvt:', 409 self.printevent(event) 410 411 def do_suspendresume(self, event): 412 (what, message, when, where, modifiers) = event 413 wid = MyFrontWindow() 414 if wid and wid in self._windows: 415 window = self._windows[wid] 416 window.do_activate(message & 1, event) 417 418 def do_kHighLevelEvent(self, event): 419 (what, message, when, where, modifiers) = event 420 if DEBUG: 421 print "High Level Event:", 422 self.printevent(event) 423 try: 424 AEProcessAppleEvent(event) 425 except: 426 pass 427 #print "AEProcessAppleEvent error:" 428 #traceback.print_exc() 429 430 def do_unknownevent(self, event): 431 if DEBUG: 432 print "Unhandled event:", 433 self.printevent(event) 434 435 def printevent(self, event): 436 (what, message, when, where, modifiers) = event 437 nicewhat = repr(what) 438 if what in eventname: 439 nicewhat = eventname[what] 440 print nicewhat, 441 if what == kHighLevelEvent: 442 h, v = where 443 print repr(ostypecode(message)), hex(when), repr(ostypecode(h | (v<<16))), 444 else: 445 print hex(message), hex(when), where, 446 print hex(modifiers) 447 448 449class MenuBar: 450 """Represent a set of menus in a menu bar. 451 452 Interface: 453 454 - (constructor) 455 - (destructor) 456 - addmenu 457 - addpopup (normally used internally) 458 - dispatch (called from Application) 459 """ 460 461 nextid = 1 # Necessarily a class variable 462 463 def getnextid(self): 464 id = MenuBar.nextid 465 MenuBar.nextid = id+1 466 return id 467 468 def __init__(self, parent=None): 469 self.parent = parent 470 ClearMenuBar() 471 self.bar = GetMenuBar() 472 self.menus = {} 473 474 # XXX necessary? 475 def close(self): 476 self.parent = None 477 self.bar = None 478 self.menus = None 479 480 def addmenu(self, title, after = 0, id=None): 481 if id is None: 482 id = self.getnextid() 483 if DEBUG: print 'Newmenu', title, id # XXXX 484 m = NewMenu(id, title) 485 m.InsertMenu(after) 486 if after >= 0: 487 if self.parent: 488 self.parent.needmenubarredraw = 1 489 else: 490 DrawMenuBar() 491 return id, m 492 493 def delmenu(self, id): 494 if DEBUG: print 'Delmenu', id # XXXX 495 DeleteMenu(id) 496 497 def addpopup(self, title = ''): 498 return self.addmenu(title, -1) 499 500# Useless: 501# def install(self): 502# if not self.bar: return 503# SetMenuBar(self.bar) 504# if self.parent: 505# self.parent.needmenubarredraw = 1 506# else: 507# DrawMenuBar() 508 509 def fixmenudimstate(self): 510 for m in self.menus.keys(): 511 menu = self.menus[m] 512 if menu.__class__ == FrameWork.AppleMenu: 513 continue 514 for i in range(len(menu.items)): 515 label, shortcut, callback, kind = menu.items[i] 516 if type(callback) == types.StringType: 517 wid = MyFrontWindow() 518 if wid and wid in self.parent._windows: 519 window = self.parent._windows[wid] 520 if hasattr(window, "domenu_" + callback): 521 menu.menu.EnableMenuItem(i + 1) 522 elif hasattr(self.parent, "domenu_" + callback): 523 menu.menu.EnableMenuItem(i + 1) 524 else: 525 menu.menu.DisableMenuItem(i + 1) 526 elif hasattr(self.parent, "domenu_" + callback): 527 menu.menu.EnableMenuItem(i + 1) 528 else: 529 menu.menu.DisableMenuItem(i + 1) 530 elif callback: 531 pass 532 533 def dispatch(self, id, item, window, event): 534 if id in self.menus: 535 self.menus[id].dispatch(id, item, window, event) 536 else: 537 if DEBUG: print "MenuBar.dispatch(%d, %d, %s, %s)" % \ 538 (id, item, window, event) 539 540 541# XXX Need a way to get menus as resources and bind them to callbacks 542 543class Menu: 544 "One menu." 545 546 def __init__(self, bar, title, after=0, id=None): 547 self.bar = bar 548 self.id, self.menu = self.bar.addmenu(title, after, id) 549 bar.menus[self.id] = self 550 self.items = [] 551 self._parent = None 552 553 def delete(self): 554 self.bar.delmenu(self.id) 555 del self.bar.menus[self.id] 556 self.menu.DisposeMenu() 557 del self.bar 558 del self.items 559 del self.menu 560 del self.id 561 del self._parent 562 563 def additem(self, label, shortcut=None, callback=None, kind=None): 564 self.menu.AppendMenu('x') # add a dummy string 565 self.items.append((label, shortcut, callback, kind)) 566 item = len(self.items) 567 if isinstance(label, unicode): 568 self.menu.SetMenuItemTextWithCFString(item, label) 569 else: 570 self.menu.SetMenuItemText(item, label) 571 if shortcut and type(shortcut) == type(()): 572 modifiers, char = shortcut[:2] 573 self.menu.SetItemCmd(item, ord(char)) 574 self.menu.SetMenuItemModifiers(item, modifiers) 575 if len(shortcut) > 2: 576 self.menu.SetMenuItemKeyGlyph(item, shortcut[2]) 577 elif shortcut: 578 self.menu.SetItemCmd(item, ord(shortcut)) 579 return item 580 581 def delitem(self, item): 582 if item != len(self.items): 583 raise 'Can only delete last item of a menu' 584 self.menu.DeleteMenuItem(item) 585 del self.items[item-1] 586 587 def addcheck(self, label, shortcut=None, callback=None): 588 return self.additem(label, shortcut, callback, 'check') 589 590 def addradio(self, label, shortcut=None, callback=None): 591 return self.additem(label, shortcut, callback, 'radio') 592 593 def addseparator(self): 594 self.menu.AppendMenu('(-') 595 self.items.append(('', None, None, 'separator')) 596 597 def addsubmenu(self, label, title=''): 598 sub = Menu(self.bar, title, -1) 599 item = self.additem(label, '\x1B', None, 'submenu') 600 self.menu.SetItemMark(item, sub.id) 601 sub._parent = self 602 sub._parent_item = item 603 return sub 604 605 def dispatch(self, id, item, window, event): 606 title, shortcut, callback, mtype = self.items[item-1] 607 if callback: 608 if not self.bar.parent or type(callback) != types.StringType: 609 menuhandler = callback 610 else: 611 # callback is string 612 wid = MyFrontWindow() 613 if wid and wid in self.bar.parent._windows: 614 window = self.bar.parent._windows[wid] 615 if hasattr(window, "domenu_" + callback): 616 menuhandler = getattr(window, "domenu_" + callback) 617 elif hasattr(self.bar.parent, "domenu_" + callback): 618 menuhandler = getattr(self.bar.parent, "domenu_" + callback) 619 else: 620 # nothing we can do. we shouldn't have come this far 621 # since the menu item should have been disabled... 622 return 623 elif hasattr(self.bar.parent, "domenu_" + callback): 624 menuhandler = getattr(self.bar.parent, "domenu_" + callback) 625 else: 626 # nothing we can do. we shouldn't have come this far 627 # since the menu item should have been disabled... 628 return 629 menuhandler(id, item, window, event) 630 631 def enable(self, onoff): 632 if onoff: 633 self.menu.EnableMenuItem(0) 634 if self._parent: 635 self._parent.menu.EnableMenuItem(self._parent_item) 636 else: 637 self.menu.DisableMenuItem(0) 638 if self._parent: 639 self._parent.menu.DisableMenuItem(self._parent_item) 640 if self.bar and self.bar.parent: 641 self.bar.parent.needmenubarredraw = 1 642 643class PopupMenu(Menu): 644 def __init__(self, bar): 645 Menu.__init__(self, bar, '(popup)', -1) 646 647 def popup(self, x, y, event, default=1, window=None): 648 # NOTE that x and y are global coordinates, and they should probably 649 # be topleft of the button the user clicked (not mouse-coordinates), 650 # so the popup nicely overlaps. 651 reply = self.menu.PopUpMenuSelect(x, y, default) 652 if not reply: 653 return 654 id = (reply >> 16) & 0xffff 655 item = reply & 0xffff 656 if not window: 657 wid = MyFrontWindow() 658 try: 659 window = self.bar.parent._windows[wid] 660 except: 661 pass # If we can't find the window we pass None 662 self.dispatch(id, item, window, event) 663 664class MenuItem: 665 def __init__(self, menu, title, shortcut=None, callback=None, kind=None): 666 self.item = menu.additem(title, shortcut, callback) 667 self.menu = menu 668 669 def delete(self): 670 self.menu.delitem(self.item) 671 del self.menu 672 del self.item 673 674 def check(self, onoff): 675 self.menu.menu.CheckMenuItem(self.item, onoff) 676 677 def enable(self, onoff): 678 if onoff: 679 self.menu.menu.EnableMenuItem(self.item) 680 else: 681 self.menu.menu.DisableMenuItem(self.item) 682 683 def settext(self, text): 684 self.menu.menu.SetMenuItemText(self.item, text) 685 686 def setstyle(self, style): 687 self.menu.menu.SetItemStyle(self.item, style) 688 689 def seticon(self, icon): 690 self.menu.menu.SetItemIcon(self.item, icon) 691 692 def setcmd(self, cmd): 693 self.menu.menu.SetItemCmd(self.item, cmd) 694 695 def setmark(self, cmd): 696 self.menu.menu.SetItemMark(self.item, cmd) 697 698 699class RadioItem(MenuItem): 700 def __init__(self, menu, title, shortcut=None, callback=None): 701 MenuItem.__init__(self, menu, title, shortcut, callback, 'radio') 702 703class CheckItem(MenuItem): 704 def __init__(self, menu, title, shortcut=None, callback=None): 705 MenuItem.__init__(self, menu, title, shortcut, callback, 'check') 706 707def Separator(menu): 708 menu.addseparator() 709 710def SubMenu(menu, label, title=''): 711 return menu.addsubmenu(label, title) 712 713 714class AppleMenu(Menu): 715 716 def __init__(self, bar, abouttext="About me...", aboutcallback=None): 717 Menu.__init__(self, bar, "\024", id=SIOUX_APPLEMENU_ID) 718 if MacOS.runtimemodel == 'ppc': 719 self.additem(abouttext, None, aboutcallback) 720 self.addseparator() 721 self.menu.AppendResMenu('DRVR') 722 else: 723 # Additem()'s tricks do not work for "apple" menu under Carbon 724 self.menu.InsertMenuItem(abouttext, 0) 725 self.items.append((abouttext, None, aboutcallback, None)) 726 727 def dispatch(self, id, item, window, event): 728 if item == 1: 729 Menu.dispatch(self, id, item, window, event) 730 elif MacOS.runtimemodel == 'ppc': 731 name = self.menu.GetMenuItemText(item) 732 OpenDeskAcc(name) 733 734class HelpMenu(Menu): 735 def __init__(self, bar): 736 # Note we don't call Menu.__init__, we do the necessary things by hand 737 self.bar = bar 738 self.menu, index = HMGetHelpMenu() 739 self.id = self.menu.GetMenuID() 740 bar.menus[self.id] = self 741 # The next line caters for the entries the system already handles for us 742 self.items = [None]*(index-1) 743 self._parent = None 744 745 746class Window: 747 """A single window belonging to an application""" 748 749 def __init__(self, parent): 750 self.wid = None 751 self.parent = parent 752 753 def open(self, bounds=(40, 40, 400, 400), resid=None): 754 if resid != None: 755 self.wid = GetNewWindow(resid, -1) 756 else: 757 self.wid = NewWindow(bounds, self.__class__.__name__, 1, 758 8, -1, 1, 0) # changed to proc id 8 to include zoom box. jvr 759 self.do_postopen() 760 761 def do_postopen(self): 762 """Tell our parent we exist""" 763 self.parent.appendwindow(self.wid, self) 764 765 def close(self): 766 self.do_postclose() 767 768 def do_postclose(self): 769 self.parent.removewindow(self.wid) 770 self.parent = None 771 self.wid = None 772 773 def SetPort(self): 774 # Convinience method 775 SetPort(self.wid) 776 777 def GetWindow(self): 778 return self.wid 779 780 def do_inDrag(self, partcode, window, event): 781 where = event[3] 782 window.DragWindow(where, self.draglimit) 783 784 draglimit = screenbounds 785 786 def do_inGoAway(self, partcode, window, event): 787 where = event[3] 788 if window.TrackGoAway(where): 789 self.close() 790 791 def do_inZoom(self, partcode, window, event): 792 (what, message, when, where, modifiers) = event 793 if window.TrackBox(where, partcode): 794 window.ZoomWindow(partcode, 1) 795 rect = window.GetWindowUserState() # so that zoom really works... jvr 796 self.do_postresize(rect[2] - rect[0], rect[3] - rect[1], window) # jvr 797 798 def do_inZoomIn(self, partcode, window, event): 799 SetPort(window) # !!! 800 self.do_inZoom(partcode, window, event) 801 802 def do_inZoomOut(self, partcode, window, event): 803 SetPort(window) # !!! 804 self.do_inZoom(partcode, window, event) 805 806 def do_inGrow(self, partcode, window, event): 807 (what, message, when, where, modifiers) = event 808 result = window.GrowWindow(where, self.growlimit) 809 if result: 810 height = (result>>16) & 0xffff # Hi word 811 width = result & 0xffff # Lo word 812 self.do_resize(width, height, window) 813 814 growlimit = (50, 50, screenbounds[2] - screenbounds[0], screenbounds[3] - screenbounds[1]) # jvr 815 816 def do_resize(self, width, height, window): 817 l, t, r, b = self.wid.GetWindowPort().GetPortBounds() # jvr, forGrowIcon 818 self.SetPort() # jvr 819 self.wid.InvalWindowRect((r - SCROLLBARWIDTH + 1, b - SCROLLBARWIDTH + 1, r, b)) # jvr 820 window.SizeWindow(width, height, 1) # changed updateFlag to true jvr 821 self.do_postresize(width, height, window) 822 823 def do_postresize(self, width, height, window): 824 SetPort(window) 825 self.wid.InvalWindowRect(window.GetWindowPort().GetPortBounds()) 826 827 def do_inContent(self, partcode, window, event): 828 # 829 # If we're not frontmost, select ourselves and wait for 830 # the activate event. 831 # 832 if MyFrontWindow() != window: 833 window.SelectWindow() 834 return 835 # We are. Handle the event. 836 (what, message, when, where, modifiers) = event 837 SetPort(window) 838 local = GlobalToLocal(where) 839 self.do_contentclick(local, modifiers, event) 840 841 def do_contentclick(self, local, modifiers, event): 842 if DEBUG: 843 print 'Click in contents at %s, modifiers %s'%(local, modifiers) 844 845 def do_rawupdate(self, window, event): 846 if DEBUG: print "raw update for", window 847 SetPort(window) 848 window.BeginUpdate() 849 self.do_update(window, event) 850 window.EndUpdate() 851 852 def do_update(self, window, event): 853 if DEBUG: 854 import time 855 for i in range(8): 856 time.sleep(0.1) 857 InvertRgn(window.GetWindowPort().visRgn) 858 FillRgn(window.GetWindowPort().visRgn, GetQDGlobalsGray()) 859 else: 860 EraseRgn(window.GetWindowPort().visRgn) 861 862 def do_activate(self, activate, event): 863 if DEBUG: print 'Activate %d for %s'%(activate, self.wid) 864 865class ControlsWindow(Window): 866 867 def do_rawupdate(self, window, event): 868 if DEBUG: print "raw update for", window 869 SetPort(window) 870 window.BeginUpdate() 871 self.do_update(window, event) 872 #DrawControls(window) # jvr 873 UpdateControls(window, window.GetWindowPort().visRgn) # jvr 874 window.DrawGrowIcon() 875 window.EndUpdate() 876 877 def do_controlhit(self, window, control, pcode, event): 878 if DEBUG: print "control hit in", window, "on", control, "; pcode =", pcode 879 880 def do_inContent(self, partcode, window, event): 881 if MyFrontWindow() != window: 882 window.SelectWindow() 883 return 884 (what, message, when, where, modifiers) = event 885 SetPort(window) # XXXX Needed? 886 local = GlobalToLocal(where) 887 pcode, control = FindControl(local, window) 888 if pcode and control: 889 self.do_rawcontrolhit(window, control, pcode, local, event) 890 else: 891 if DEBUG: print "FindControl(%s, %s) -> (%s, %s)" % \ 892 (local, window, pcode, control) 893 self.do_contentclick(local, modifiers, event) 894 895 def do_rawcontrolhit(self, window, control, pcode, local, event): 896 pcode = control.TrackControl(local) 897 if pcode: 898 self.do_controlhit(window, control, pcode, event) 899 900class ScrolledWindow(ControlsWindow): 901 def __init__(self, parent): 902 self.barx = self.bary = None 903 self.barx_enabled = self.bary_enabled = 1 904 self.activated = 1 905 ControlsWindow.__init__(self, parent) 906 907 def scrollbars(self, wantx=1, wanty=1): 908 SetPort(self.wid) 909 self.barx = self.bary = None 910 self.barx_enabled = self.bary_enabled = 1 911 x0, y0, x1, y1 = self.wid.GetWindowPort().GetPortBounds() 912 vx, vy = self.getscrollbarvalues() 913 if vx is None: self.barx_enabled, vx = 0, 0 914 if vy is None: self.bary_enabled, vy = 0, 0 915 if wantx: 916 rect = x0-1, y1-(SCROLLBARWIDTH-1), x1-(SCROLLBARWIDTH-2), y1+1 917 self.barx = NewControl(self.wid, rect, "", 1, vx, 0, 32767, 16, 0) 918 if not self.barx_enabled: self.barx.HiliteControl(255) 919## self.wid.InvalWindowRect(rect) 920 if wanty: 921 rect = x1-(SCROLLBARWIDTH-1), y0-1, x1+1, y1-(SCROLLBARWIDTH-2) 922 self.bary = NewControl(self.wid, rect, "", 1, vy, 0, 32767, 16, 0) 923 if not self.bary_enabled: self.bary.HiliteControl(255) 924## self.wid.InvalWindowRect(rect) 925 926 def do_postclose(self): 927 self.barx = self.bary = None 928 ControlsWindow.do_postclose(self) 929 930 def do_activate(self, onoff, event): 931 self.activated = onoff 932 if onoff: 933 if self.barx and self.barx_enabled: 934 self.barx.ShowControl() # jvr 935 if self.bary and self.bary_enabled: 936 self.bary.ShowControl() # jvr 937 else: 938 if self.barx: 939 self.barx.HideControl() # jvr; An inactive window should have *hidden* 940 # scrollbars, not just dimmed (no matter what 941 # BBEdit does... look at the Finder) 942 if self.bary: 943 self.bary.HideControl() # jvr 944 self.wid.DrawGrowIcon() # jvr 945 946 def do_postresize(self, width, height, window): 947 l, t, r, b = self.wid.GetWindowPort().GetPortBounds() 948 self.SetPort() 949 if self.barx: 950 self.barx.HideControl() # jvr 951 self.barx.MoveControl(l-1, b-(SCROLLBARWIDTH-1)) 952 self.barx.SizeControl((r-l)-(SCROLLBARWIDTH-3), SCROLLBARWIDTH) # jvr 953 if self.bary: 954 self.bary.HideControl() # jvr 955 self.bary.MoveControl(r-(SCROLLBARWIDTH-1), t-1) 956 self.bary.SizeControl(SCROLLBARWIDTH, (b-t)-(SCROLLBARWIDTH-3)) # jvr 957 if self.barx: 958 self.barx.ShowControl() # jvr 959 self.wid.ValidWindowRect((l, b - SCROLLBARWIDTH + 1, r - SCROLLBARWIDTH + 2, b)) # jvr 960 if self.bary: 961 self.bary.ShowControl() # jvr 962 self.wid.ValidWindowRect((r - SCROLLBARWIDTH + 1, t, r, b - SCROLLBARWIDTH + 2)) # jvr 963 self.wid.InvalWindowRect((r - SCROLLBARWIDTH + 1, b - SCROLLBARWIDTH + 1, r, b)) # jvr, growicon 964 965 966 def do_rawcontrolhit(self, window, control, pcode, local, event): 967 if control == self.barx: 968 which = 'x' 969 elif control == self.bary: 970 which = 'y' 971 else: 972 return 0 973 if pcode in (inUpButton, inDownButton, inPageUp, inPageDown): 974 # We do the work for the buttons and grey area in the tracker 975 dummy = control.TrackControl(local, self.do_controltrack) 976 else: 977 # but the thumb is handled here 978 pcode = control.TrackControl(local) 979 if pcode == inThumb: 980 value = control.GetControlValue() 981 print 'setbars', which, value #DBG 982 self.scrollbar_callback(which, 'set', value) 983 self.updatescrollbars() 984 else: 985 print 'funny part', pcode #DBG 986 return 1 987 988 def do_controltrack(self, control, pcode): 989 if control == self.barx: 990 which = 'x' 991 elif control == self.bary: 992 which = 'y' 993 else: 994 return 995 996 if pcode == inUpButton: 997 what = '-' 998 elif pcode == inDownButton: 999 what = '+' 1000 elif pcode == inPageUp: 1001 what = '--' 1002 elif pcode == inPageDown: 1003 what = '++' 1004 else: 1005 return 1006 self.scrollbar_callback(which, what, None) 1007 self.updatescrollbars() 1008 1009 def updatescrollbars(self): 1010 SetPort(self.wid) 1011 vx, vy = self.getscrollbarvalues() 1012 if self.barx: 1013 if vx is None: 1014 self.barx.HiliteControl(255) 1015 self.barx_enabled = 0 1016 else: 1017 if not self.barx_enabled: 1018 self.barx_enabled = 1 1019 if self.activated: 1020 self.barx.HiliteControl(0) 1021 self.barx.SetControlValue(vx) 1022 if self.bary: 1023 if vy is None: 1024 self.bary.HiliteControl(255) 1025 self.bary_enabled = 0 1026 else: 1027 if not self.bary_enabled: 1028 self.bary_enabled = 1 1029 if self.activated: 1030 self.bary.HiliteControl(0) 1031 self.bary.SetControlValue(vy) 1032 1033 # Auxiliary function: convert standard text/image/etc coordinate 1034 # to something palatable as getscrollbarvalues() return 1035 def scalebarvalue(self, absmin, absmax, curmin, curmax): 1036 if curmin <= absmin and curmax >= absmax: 1037 return None 1038 if curmin <= absmin: 1039 return 0 1040 if curmax >= absmax: 1041 return 32767 1042 perc = float(curmin-absmin)/float(absmax-absmin) 1043 return int(perc*32767) 1044 1045 # To be overridden: 1046 1047 def getscrollbarvalues(self): 1048 return 0, 0 1049 1050 def scrollbar_callback(self, which, what, value): 1051 print 'scroll', which, what, value 1052 1053class DialogWindow(Window): 1054 """A modeless dialog window""" 1055 1056 def open(self, resid): 1057 self.dlg = GetNewDialog(resid, -1) 1058 self.wid = self.dlg.GetDialogWindow() 1059 self.do_postopen() 1060 1061 def close(self): 1062 self.do_postclose() 1063 1064 def do_postclose(self): 1065 self.dlg = None 1066 Window.do_postclose(self) 1067 1068 def do_itemhit(self, item, event): 1069 print 'Dialog %s, item %d hit'%(self.dlg, item) 1070 1071 def do_rawupdate(self, window, event): 1072 pass 1073 1074def ostypecode(x): 1075 "Convert a long int to the 4-character code it really is" 1076 s = '' 1077 for i in range(4): 1078 x, c = divmod(x, 256) 1079 s = chr(c) + s 1080 return s 1081 1082 1083class TestApp(Application): 1084 1085 "This class is used by the test() function" 1086 1087 def makeusermenus(self): 1088 self.filemenu = m = Menu(self.menubar, "File") 1089 self.saveitem = MenuItem(m, "Save", "S", self.save) 1090 Separator(m) 1091 self.optionsmenu = mm = SubMenu(m, "Options") 1092 self.opt1 = CheckItem(mm, "Arguments", "A") 1093 self.opt2 = CheckItem(mm, "Being hit on the head lessons", (kMenuOptionModifier, "A")) 1094 self.opt3 = CheckItem(mm, "Complaints", (kMenuOptionModifier|kMenuNoCommandModifier, "A")) 1095 Separator(m) 1096 self.itemeh = MenuItem(m, "Enable Help", None, self.enablehelp) 1097 self.itemdbg = MenuItem(m, "Debug", None, self.debug) 1098 Separator(m) 1099 self.quititem = MenuItem(m, "Quit", "Q", self.quit) 1100 1101 def save(self, *args): 1102 print "Save" 1103 1104 def quit(self, *args): 1105 raise self 1106 1107 def enablehelp(self, *args): 1108 hm = self.gethelpmenu() 1109 self.nohelpitem = MenuItem(hm, "There isn't any", None, self.nohelp) 1110 1111 def nohelp(self, *args): 1112 print "I told you there isn't any!" 1113 1114 def debug(self, *args): 1115 import pdb 1116 pdb.set_trace() 1117 1118 1119def test(): 1120 "Test program" 1121 app = TestApp() 1122 app.mainloop() 1123 1124 1125if __name__ == '__main__': 1126 test() 1127