diff options
author | Jack Jansen <jack.jansen@cwi.nl> | 2002-12-30 22:04:23 (GMT) |
---|---|---|
committer | Jack Jansen <jack.jansen@cwi.nl> | 2002-12-30 22:04:23 (GMT) |
commit | 60087fb45092d9c199cea162e58d9193c7c1558c (patch) | |
tree | 05f3343e7707c4a4179e409506b39601279f04c1 /Lib/plat-mac/FrameWork.py | |
parent | c262a1f51ce89dbea4aeb072cf631686c47ed97f (diff) | |
download | cpython-60087fb45092d9c199cea162e58d9193c7c1558c.zip cpython-60087fb45092d9c199cea162e58d9193c7c1558c.tar.gz cpython-60087fb45092d9c199cea162e58d9193c7c1558c.tar.bz2 |
Moved most of Mac/Lib hierarchy to Lib/plat-mac: it can be used both
in MacPython-OS9 and MacPython-OSX (or the equivalent unix Python on
Mac OS X). The only items remaining in Mac/Lib are modules that are
meaningful only for MacPython-OS9 (CFM stuff, MacPython preferences
in resources, etc).
Diffstat (limited to 'Lib/plat-mac/FrameWork.py')
-rw-r--r-- | Lib/plat-mac/FrameWork.py | 1120 |
1 files changed, 1120 insertions, 0 deletions
diff --git a/Lib/plat-mac/FrameWork.py b/Lib/plat-mac/FrameWork.py new file mode 100644 index 0000000..24acd41 --- /dev/null +++ b/Lib/plat-mac/FrameWork.py @@ -0,0 +1,1120 @@ +"A sort of application framework for the Mac" + +DEBUG=0 + +import MacOS +import traceback + +from Carbon.AE import * +from Carbon.AppleEvents import * +from Carbon.Ctl import * +from Carbon.Controls import * +from Carbon.Dlg import * +from Carbon.Dialogs import * +from Carbon.Evt import * +from Carbon.Events import * +from Carbon.Help import * +from Carbon.Menu import * +from Carbon.Menus import * +from Carbon.Qd import * +from Carbon.QuickDraw import * +#from Carbon.Res import * +#from Carbon.Resources import * +#from Carbon.Snd import * +#from Carbon.Sound import * +from Carbon.Win import * +from Carbon.Windows import * +import types + +import EasyDialogs + +try: + MyFrontWindow = FrontNonFloatingWindow +except NameError: + MyFrontWindow = FrontWindow + +kHighLevelEvent = 23 # Don't know what header file this should come from +SCROLLBARWIDTH = 16 # Again, not a clue... + +# Trick to forestall a set of SIOUX menus being added to our menubar +SIOUX_APPLEMENU_ID=32000 + + +# Map event 'what' field to strings +eventname = {} +eventname[1] = 'mouseDown' +eventname[2] = 'mouseUp' +eventname[3] = 'keyDown' +eventname[4] = 'keyUp' +eventname[5] = 'autoKey' +eventname[6] = 'updateEvt' +eventname[7] = 'diskEvt' +eventname[8] = 'activateEvt' +eventname[15] = 'osEvt' +eventname[23] = 'kHighLevelEvent' + +# Map part codes returned by WhichWindow() to strings +partname = {} +partname[0] = 'inDesk' +partname[1] = 'inMenuBar' +partname[2] = 'inSysWindow' +partname[3] = 'inContent' +partname[4] = 'inDrag' +partname[5] = 'inGrow' +partname[6] = 'inGoAway' +partname[7] = 'inZoomIn' +partname[8] = 'inZoomOut' + +# +# The useable portion of the screen +# ## but what happens with multiple screens? jvr +screenbounds = GetQDGlobalsScreenBits().bounds +screenbounds = screenbounds[0]+4, screenbounds[1]+4, \ + screenbounds[2]-4, screenbounds[3]-4 + +next_window_x = 16 # jvr +next_window_y = 44 # jvr + +def windowbounds(width, height): + "Return sensible window bounds" + global next_window_x, next_window_y + r, b = next_window_x+width, next_window_y+height + if r > screenbounds[2]: + next_window_x = 16 + if b > screenbounds[3]: + next_window_y = 44 + l, t = next_window_x, next_window_y + r, b = next_window_x+width, next_window_y+height + next_window_x, next_window_y = next_window_x + 8, next_window_y + 20 # jvr + return l, t, r, b + +_watch = None +def setwatchcursor(): + global _watch + + if _watch == None: + _watch = GetCursor(4).data + SetCursor(_watch) + +def setarrowcursor(): + SetCursor(GetQDGlobalsArrow()) + +class Application: + + "Application framework -- your application should be a derived class" + + def __init__(self, nomenubar=0): + self._doing_asyncevents = 0 + self.quitting = 0 + self.needmenubarredraw = 0 + self._windows = {} + self._helpmenu = None + if nomenubar: + self.menubar = None + else: + self.makemenubar() + + def __del__(self): + if self._doing_asyncevents: + self._doing_asyncevents = 0 + MacOS.SetEventHandler() + + def makemenubar(self): + self.menubar = MenuBar(self) + AppleMenu(self.menubar, self.getabouttext(), self.do_about) + self.makeusermenus() + + def makeusermenus(self): + self.filemenu = m = Menu(self.menubar, "File") + self._quititem = MenuItem(m, "Quit", "Q", self._quit) + + def gethelpmenu(self): + if self._helpmenu == None: + self._helpmenu = HelpMenu(self.menubar) + return self._helpmenu + + def _quit(self, *args): + self.quitting = 1 + + def cleanup(self): + for w in self._windows.values(): + w.do_close() + return self._windows == {} + + def appendwindow(self, wid, window): + self._windows[wid] = window + + def removewindow(self, wid): + del self._windows[wid] + + def getabouttext(self): + return "About %s..." % self.__class__.__name__ + + def do_about(self, id, item, window, event): + EasyDialogs.Message("Hello, world!" + "\015(%s)" % self.__class__.__name__) + + # The main event loop is broken up in several simple steps. + # This is done so you can override each individual part, + # if you have a need to do extra processing independent of the + # event type. + # Normally, however, you'd just define handlers for individual + # events. + + schedparams = (0, 0) # By default disable Python's event handling + default_wait = None # By default we wait GetCaretTime in WaitNextEvent + + def mainloop(self, mask = everyEvent, wait = None): + self.quitting = 0 + if hasattr(MacOS, 'SchedParams'): + saveparams = apply(MacOS.SchedParams, self.schedparams) + try: + while not self.quitting: + try: + self.do1event(mask, wait) + except (Application, SystemExit): + # Note: the raising of "self" is old-fashioned idiom to + # exit the mainloop. Calling _quit() is better for new + # applications. + break + finally: + if hasattr(MacOS, 'SchedParams'): + apply(MacOS.SchedParams, saveparams) + + def dopendingevents(self, mask = everyEvent): + """dopendingevents - Handle all pending events""" + while self.do1event(mask, wait=0): + pass + + def do1event(self, mask = everyEvent, wait = None): + ok, event = self.getevent(mask, wait) + if IsDialogEvent(event): + if self.do_dialogevent(event): + return + if ok: + self.dispatch(event) + else: + self.idle(event) + + def idle(self, event): + pass + + def getevent(self, mask = everyEvent, wait = None): + if self.needmenubarredraw: + DrawMenuBar() + self.needmenubarredraw = 0 + if wait is None: + wait = self.default_wait + if wait is None: + wait = GetCaretTime() + ok, event = WaitNextEvent(mask, wait) + return ok, event + + def dispatch(self, event): + # The following appears to be double work (already done in do1event) + # but we need it for asynchronous event handling + if IsDialogEvent(event): + if self.do_dialogevent(event): + return + (what, message, when, where, modifiers) = event + if eventname.has_key(what): + name = "do_" + eventname[what] + else: + name = "do_%d" % what + try: + handler = getattr(self, name) + except AttributeError: + handler = self.do_unknownevent + handler(event) + + def asyncevents(self, onoff): + """asyncevents - Set asynchronous event handling on or off""" + if MacOS.runtimemodel == 'macho': + raise 'Unsupported in MachoPython' + old = self._doing_asyncevents + if old: + MacOS.SetEventHandler() + apply(MacOS.SchedParams, self.schedparams) + if onoff: + MacOS.SetEventHandler(self.dispatch) + doint, dummymask, benice, howoften, bgyield = \ + self.schedparams + MacOS.SchedParams(doint, everyEvent, benice, + howoften, bgyield) + self._doing_asyncevents = onoff + return old + + def do_dialogevent(self, event): + gotone, dlg, item = DialogSelect(event) + if gotone: + window = dlg.GetDialogWindow() + if self._windows.has_key(window): + self._windows[window].do_itemhit(item, event) + else: + print 'Dialog event for unknown dialog' + return 1 + return 0 + + def do_mouseDown(self, event): + (what, message, when, where, modifiers) = event + partcode, wid = FindWindow(where) + + # + # Find the correct name. + # + if partname.has_key(partcode): + name = "do_" + partname[partcode] + else: + name = "do_%d" % partcode + + if wid == None: + # No window, or a non-python window + try: + handler = getattr(self, name) + except AttributeError: + # Not menubar or something, so assume someone + # else's window + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + return + elif self._windows.has_key(wid): + # It is a window. Hand off to correct window. + window = self._windows[wid] + try: + handler = getattr(window, name) + except AttributeError: + handler = self.do_unknownpartcode + else: + # It is a python-toolbox window, but not ours. + handler = self.do_unknownwindow + handler(partcode, wid, event) + + def do_inSysWindow(self, partcode, window, event): + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + + def do_inDesk(self, partcode, window, event): + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + + def do_inMenuBar(self, partcode, window, event): + if not self.menubar: + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + return + (what, message, when, where, modifiers) = event + result = MenuSelect(where) + id = (result>>16) & 0xffff # Hi word + if id >= 0x8000: + id = -65536 + id + item = result & 0xffff # Lo word + self.do_rawmenu(id, item, window, event) + + def do_rawmenu(self, id, item, window, event): + try: + self.do_menu(id, item, window, event) + finally: + HiliteMenu(0) + + def do_menu(self, id, item, window, event): + if hasattr(MacOS, 'OutputSeen'): + MacOS.OutputSeen() + self.menubar.dispatch(id, item, window, event) + + + def do_unknownpartcode(self, partcode, window, event): + (what, message, when, where, modifiers) = event + if DEBUG: print "Mouse down at global:", where + if DEBUG: print "\tUnknown part code:", partcode + if DEBUG: print "\tEvent:", self.printevent(event) + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + + def do_unknownwindow(self, partcode, window, event): + if DEBUG: print 'Unknown window:', window + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + + def do_keyDown(self, event): + self.do_key(event) + + def do_autoKey(self, event): + if not event[-1] & cmdKey: + self.do_key(event) + + def do_key(self, event): + (what, message, when, where, modifiers) = event + c = chr(message & charCodeMask) + if self.menubar: + result = MenuEvent(event) + id = (result>>16) & 0xffff # Hi word + item = result & 0xffff # Lo word + if id: + self.do_rawmenu(id, item, None, event) + return + # Otherwise we fall-through + if modifiers & cmdKey: + if c == '.': + raise self + else: + if not self.menubar: + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + return + else: + # See whether the front window wants it + w = MyFrontWindow() + if w and self._windows.has_key(w): + window = self._windows[w] + try: + do_char = window.do_char + except AttributeError: + do_char = self.do_char + do_char(c, event) + # else it wasn't for us, sigh... + + def do_char(self, c, event): + if DEBUG: print "Character", `c` + + def do_updateEvt(self, event): + (what, message, when, where, modifiers) = event + wid = WhichWindow(message) + if wid and self._windows.has_key(wid): + window = self._windows[wid] + window.do_rawupdate(wid, event) + else: + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + + def do_activateEvt(self, event): + (what, message, when, where, modifiers) = event + wid = WhichWindow(message) + if wid and self._windows.has_key(wid): + window = self._windows[wid] + window.do_activate(modifiers & 1, event) + else: + if hasattr(MacOS, 'HandleEvent'): + MacOS.HandleEvent(event) + + def do_osEvt(self, event): + (what, message, when, where, modifiers) = event + which = (message >> 24) & 0xff + if which == 1: # suspend/resume + self.do_suspendresume(event) + else: + if DEBUG: + print 'unknown osEvt:', + self.printevent(event) + + def do_suspendresume(self, event): + (what, message, when, where, modifiers) = event + wid = MyFrontWindow() + if wid and self._windows.has_key(wid): + window = self._windows[wid] + window.do_activate(message & 1, event) + + def do_kHighLevelEvent(self, event): + (what, message, when, where, modifiers) = event + if DEBUG: + print "High Level Event:", + self.printevent(event) + try: + AEProcessAppleEvent(event) + except: + pass + #print "AEProcessAppleEvent error:" + #traceback.print_exc() + + def do_unknownevent(self, event): + if DEBUG: + print "Unhandled event:", + self.printevent(event) + + def printevent(self, event): + (what, message, when, where, modifiers) = event + nicewhat = `what` + if eventname.has_key(what): + nicewhat = eventname[what] + print nicewhat, + if what == kHighLevelEvent: + h, v = where + print `ostypecode(message)`, hex(when), `ostypecode(h | (v<<16))`, + else: + print hex(message), hex(when), where, + print hex(modifiers) + + +class MenuBar: + """Represent a set of menus in a menu bar. + + Interface: + + - (constructor) + - (destructor) + - addmenu + - addpopup (normally used internally) + - dispatch (called from Application) + """ + + nextid = 1 # Necessarily a class variable + + def getnextid(self): + id = MenuBar.nextid + MenuBar.nextid = id+1 + return id + + def __init__(self, parent=None): + self.parent = parent + ClearMenuBar() + self.bar = GetMenuBar() + self.menus = {} + + # XXX necessary? + def close(self): + self.parent = None + self.bar = None + self.menus = None + + def addmenu(self, title, after = 0, id=None): + if id == None: + id = self.getnextid() + if DEBUG: print 'Newmenu', title, id # XXXX + m = NewMenu(id, title) + m.InsertMenu(after) + if after >= 0: + if self.parent: + self.parent.needmenubarredraw = 1 + else: + DrawMenuBar() + return id, m + + def delmenu(self, id): + if DEBUG: print 'Delmenu', id # XXXX + DeleteMenu(id) + + def addpopup(self, title = ''): + return self.addmenu(title, -1) + +# Useless: +# def install(self): +# if not self.bar: return +# SetMenuBar(self.bar) +# if self.parent: +# self.parent.needmenubarredraw = 1 +# else: +# DrawMenuBar() + + def fixmenudimstate(self): + for m in self.menus.keys(): + menu = self.menus[m] + if menu.__class__ == FrameWork.AppleMenu: + continue + for i in range(len(menu.items)): + label, shortcut, callback, kind = menu.items[i] + if type(callback) == types.StringType: + wid = MyFrontWindow() + if wid and self.parent._windows.has_key(wid): + window = self.parent._windows[wid] + if hasattr(window, "domenu_" + callback): + menu.menu.EnableMenuItem(i + 1) + elif hasattr(self.parent, "domenu_" + callback): + menu.menu.EnableMenuItem(i + 1) + else: + menu.menu.DisableMenuItem(i + 1) + elif hasattr(self.parent, "domenu_" + callback): + menu.menu.EnableMenuItem(i + 1) + else: + menu.menu.DisableMenuItem(i + 1) + elif callback: + pass + + def dispatch(self, id, item, window, event): + if self.menus.has_key(id): + self.menus[id].dispatch(id, item, window, event) + else: + if DEBUG: print "MenuBar.dispatch(%d, %d, %s, %s)" % \ + (id, item, window, event) + + +# XXX Need a way to get menus as resources and bind them to callbacks + +class Menu: + "One menu." + + def __init__(self, bar, title, after=0, id=None): + self.bar = bar + self.id, self.menu = self.bar.addmenu(title, after, id) + bar.menus[self.id] = self + self.items = [] + self._parent = None + + def delete(self): + self.bar.delmenu(self.id) + del self.bar.menus[self.id] + self.menu.DisposeMenu() + del self.bar + del self.items + del self.menu + del self.id + del self._parent + + def additem(self, label, shortcut=None, callback=None, kind=None): + self.menu.AppendMenu('x') # add a dummy string + self.items.append((label, shortcut, callback, kind)) + item = len(self.items) + self.menu.SetMenuItemText(item, label) # set the actual text + if shortcut and type(shortcut) == type(()): + modifiers, char = shortcut[:2] + self.menu.SetItemCmd(item, ord(char)) + self.menu.SetMenuItemModifiers(item, modifiers) + if len(shortcut) > 2: + self.menu.SetMenuItemKeyGlyph(item, shortcut[2]) + elif shortcut: + self.menu.SetItemCmd(item, ord(shortcut)) + return item + + def delitem(self, item): + if item != len(self.items): + raise 'Can only delete last item of a menu' + self.menu.DeleteMenuItem(item) + del self.items[item-1] + + def addcheck(self, label, shortcut=None, callback=None): + return self.additem(label, shortcut, callback, 'check') + + def addradio(self, label, shortcut=None, callback=None): + return self.additem(label, shortcut, callback, 'radio') + + def addseparator(self): + self.menu.AppendMenu('(-') + self.items.append(('', None, None, 'separator')) + + def addsubmenu(self, label, title=''): + sub = Menu(self.bar, title, -1) + item = self.additem(label, '\x1B', None, 'submenu') + self.menu.SetItemMark(item, sub.id) + sub._parent = self + sub._parent_item = item + return sub + + def dispatch(self, id, item, window, event): + title, shortcut, callback, mtype = self.items[item-1] + if callback: + if not self.bar.parent or type(callback) <> types.StringType: + menuhandler = callback + else: + # callback is string + wid = MyFrontWindow() + if wid and self.bar.parent._windows.has_key(wid): + window = self.bar.parent._windows[wid] + if hasattr(window, "domenu_" + callback): + menuhandler = getattr(window, "domenu_" + callback) + elif hasattr(self.bar.parent, "domenu_" + callback): + menuhandler = getattr(self.bar.parent, "domenu_" + callback) + else: + # nothing we can do. we shouldn't have come this far + # since the menu item should have been disabled... + return + elif hasattr(self.bar.parent, "domenu_" + callback): + menuhandler = getattr(self.bar.parent, "domenu_" + callback) + else: + # nothing we can do. we shouldn't have come this far + # since the menu item should have been disabled... + return + menuhandler(id, item, window, event) + + def enable(self, onoff): + if onoff: + self.menu.EnableMenuItem(0) + if self._parent: + self._parent.menu.EnableMenuItem(self._parent_item) + else: + self.menu.DisableMenuItem(0) + if self._parent: + self._parent.menu.DisableMenuItem(self._parent_item) + if self.bar and self.bar.parent: + self.bar.parent.needmenubarredraw = 1 + +class PopupMenu(Menu): + def __init__(self, bar): + Menu.__init__(self, bar, '(popup)', -1) + + def popup(self, x, y, event, default=1, window=None): + # NOTE that x and y are global coordinates, and they should probably + # be topleft of the button the user clicked (not mouse-coordinates), + # so the popup nicely overlaps. + reply = self.menu.PopUpMenuSelect(x, y, default) + if not reply: + return + id = (reply & 0xffff0000) >> 16 + item = reply & 0xffff + if not window: + wid = MyFrontWindow() + try: + window = self.bar.parent._windows[wid] + except: + pass # If we can't find the window we pass None + self.dispatch(id, item, window, event) + +class MenuItem: + def __init__(self, menu, title, shortcut=None, callback=None, kind=None): + self.item = menu.additem(title, shortcut, callback) + self.menu = menu + + def delete(self): + self.menu.delitem(self.item) + del self.menu + del self.item + + def check(self, onoff): + self.menu.menu.CheckMenuItem(self.item, onoff) + + def enable(self, onoff): + if onoff: + self.menu.menu.EnableMenuItem(self.item) + else: + self.menu.menu.DisableMenuItem(self.item) + + def settext(self, text): + self.menu.menu.SetMenuItemText(self.item, text) + + def setstyle(self, style): + self.menu.menu.SetItemStyle(self.item, style) + + def seticon(self, icon): + self.menu.menu.SetItemIcon(self.item, icon) + + def setcmd(self, cmd): + self.menu.menu.SetItemCmd(self.item, cmd) + + def setmark(self, cmd): + self.menu.menu.SetItemMark(self.item, cmd) + + +class RadioItem(MenuItem): + def __init__(self, menu, title, shortcut=None, callback=None): + MenuItem.__init__(self, menu, title, shortcut, callback, 'radio') + +class CheckItem(MenuItem): + def __init__(self, menu, title, shortcut=None, callback=None): + MenuItem.__init__(self, menu, title, shortcut, callback, 'check') + +def Separator(menu): + menu.addseparator() + +def SubMenu(menu, label, title=''): + return menu.addsubmenu(label, title) + + +class AppleMenu(Menu): + + def __init__(self, bar, abouttext="About me...", aboutcallback=None): + Menu.__init__(self, bar, "\024", id=SIOUX_APPLEMENU_ID) + if MacOS.runtimemodel == 'ppc': + self.additem(abouttext, None, aboutcallback) + self.addseparator() + self.menu.AppendResMenu('DRVR') + else: + # Additem()'s tricks do not work for "apple" menu under Carbon + self.menu.InsertMenuItem(abouttext, 0) + self.items.append((abouttext, None, aboutcallback, None)) + + def dispatch(self, id, item, window, event): + if item == 1: + Menu.dispatch(self, id, item, window, event) + elif MacOS.runtimemodel == 'ppc': + name = self.menu.GetMenuItemText(item) + OpenDeskAcc(name) + +class HelpMenu(Menu): + def __init__(self, bar): + # Note we don't call Menu.__init__, we do the necessary things by hand + self.bar = bar + self.menu, index = HMGetHelpMenu() + self.id = self.menu.GetMenuID() + bar.menus[self.id] = self + # The next line caters for the entries the system already handles for us + self.items = [None]*(index-1) + self._parent = None + + +class Window: + """A single window belonging to an application""" + + def __init__(self, parent): + self.wid = None + self.parent = parent + + def open(self, bounds=(40, 40, 400, 400), resid=None): + if resid <> None: + self.wid = GetNewWindow(resid, -1) + else: + self.wid = NewWindow(bounds, self.__class__.__name__, 1, + 8, -1, 1, 0) # changed to proc id 8 to include zoom box. jvr + self.do_postopen() + + def do_postopen(self): + """Tell our parent we exist""" + self.parent.appendwindow(self.wid, self) + + def close(self): + self.do_postclose() + + def do_postclose(self): + self.parent.removewindow(self.wid) + self.parent = None + self.wid = None + + def SetPort(self): + # Convinience method + SetPort(self.wid) + + def GetWindow(self): + return self.wid + + def do_inDrag(self, partcode, window, event): + where = event[3] + window.DragWindow(where, self.draglimit) + + draglimit = screenbounds + + def do_inGoAway(self, partcode, window, event): + where = event[3] + if window.TrackGoAway(where): + self.close() + + def do_inZoom(self, partcode, window, event): + (what, message, when, where, modifiers) = event + if window.TrackBox(where, partcode): + window.ZoomWindow(partcode, 1) + rect = window.GetWindowUserState() # so that zoom really works... jvr + self.do_postresize(rect[2] - rect[0], rect[3] - rect[1], window) # jvr + + def do_inZoomIn(self, partcode, window, event): + SetPort(window) # !!! + self.do_inZoom(partcode, window, event) + + def do_inZoomOut(self, partcode, window, event): + SetPort(window) # !!! + self.do_inZoom(partcode, window, event) + + def do_inGrow(self, partcode, window, event): + (what, message, when, where, modifiers) = event + result = window.GrowWindow(where, self.growlimit) + if result: + height = (result>>16) & 0xffff # Hi word + width = result & 0xffff # Lo word + self.do_resize(width, height, window) + + growlimit = (50, 50, screenbounds[2] - screenbounds[0], screenbounds[3] - screenbounds[1]) # jvr + + def do_resize(self, width, height, window): + l, t, r, b = self.wid.GetWindowPort().GetPortBounds() # jvr, forGrowIcon + self.SetPort() # jvr + self.wid.InvalWindowRect((r - SCROLLBARWIDTH + 1, b - SCROLLBARWIDTH + 1, r, b)) # jvr + window.SizeWindow(width, height, 1) # changed updateFlag to true jvr + self.do_postresize(width, height, window) + + def do_postresize(self, width, height, window): + SetPort(window) + self.wid.InvalWindowRect(window.GetWindowPort().GetPortBounds()) + + def do_inContent(self, partcode, window, event): + # + # If we're not frontmost, select ourselves and wait for + # the activate event. + # + if MyFrontWindow() <> window: + window.SelectWindow() + return + # We are. Handle the event. + (what, message, when, where, modifiers) = event + SetPort(window) + local = GlobalToLocal(where) + self.do_contentclick(local, modifiers, event) + + def do_contentclick(self, local, modifiers, event): + if DEBUG: + print 'Click in contents at %s, modifiers %s'%(local, modifiers) + + def do_rawupdate(self, window, event): + if DEBUG: print "raw update for", window + SetPort(window) + window.BeginUpdate() + self.do_update(window, event) + window.EndUpdate() + + def do_update(self, window, event): + if DEBUG: + import time + for i in range(8): + time.sleep(0.1) + InvertRgn(window.GetWindowPort().visRgn) + FillRgn(window.GetWindowPort().visRgn, GetQDGlobalsGray()) + else: + EraseRgn(window.GetWindowPort().visRgn) + + def do_activate(self, activate, event): + if DEBUG: print 'Activate %d for %s'%(activate, self.wid) + +class ControlsWindow(Window): + + def do_rawupdate(self, window, event): + if DEBUG: print "raw update for", window + SetPort(window) + window.BeginUpdate() + self.do_update(window, event) + #DrawControls(window) # jvr + UpdateControls(window, window.GetWindowPort().visRgn) # jvr + window.DrawGrowIcon() + window.EndUpdate() + + def do_controlhit(self, window, control, pcode, event): + if DEBUG: print "control hit in", window, "on", control, "; pcode =", pcode + + def do_inContent(self, partcode, window, event): + if MyFrontWindow() <> window: + window.SelectWindow() + return + (what, message, when, where, modifiers) = event + SetPort(window) # XXXX Needed? + local = GlobalToLocal(where) + pcode, control = FindControl(local, window) + if pcode and control: + self.do_rawcontrolhit(window, control, pcode, local, event) + else: + if DEBUG: print "FindControl(%s, %s) -> (%s, %s)" % \ + (local, window, pcode, control) + self.do_contentclick(local, modifiers, event) + + def do_rawcontrolhit(self, window, control, pcode, local, event): + pcode = control.TrackControl(local) + if pcode: + self.do_controlhit(window, control, pcode, event) + +class ScrolledWindow(ControlsWindow): + def __init__(self, parent): + self.barx = self.bary = None + self.barx_enabled = self.bary_enabled = 1 + self.activated = 1 + ControlsWindow.__init__(self, parent) + + def scrollbars(self, wantx=1, wanty=1): + SetPort(self.wid) + self.barx = self.bary = None + self.barx_enabled = self.bary_enabled = 1 + x0, y0, x1, y1 = self.wid.GetWindowPort().GetPortBounds() + vx, vy = self.getscrollbarvalues() + if vx == None: self.barx_enabled, vx = 0, 0 + if vy == None: self.bary_enabled, vy = 0, 0 + if wantx: + rect = x0-1, y1-(SCROLLBARWIDTH-1), x1-(SCROLLBARWIDTH-2), y1+1 + self.barx = NewControl(self.wid, rect, "", 1, vx, 0, 32767, 16, 0) + if not self.barx_enabled: self.barx.HiliteControl(255) +## self.wid.InvalWindowRect(rect) + if wanty: + rect = x1-(SCROLLBARWIDTH-1), y0-1, x1+1, y1-(SCROLLBARWIDTH-2) + self.bary = NewControl(self.wid, rect, "", 1, vy, 0, 32767, 16, 0) + if not self.bary_enabled: self.bary.HiliteControl(255) +## self.wid.InvalWindowRect(rect) + + def do_postclose(self): + self.barx = self.bary = None + ControlsWindow.do_postclose(self) + + def do_activate(self, onoff, event): + self.activated = onoff + if onoff: + if self.barx and self.barx_enabled: + self.barx.ShowControl() # jvr + if self.bary and self.bary_enabled: + self.bary.ShowControl() # jvr + else: + if self.barx: + self.barx.HideControl() # jvr; An inactive window should have *hidden* + # scrollbars, not just dimmed (no matter what + # BBEdit does... look at the Finder) + if self.bary: + self.bary.HideControl() # jvr + self.wid.DrawGrowIcon() # jvr + + def do_postresize(self, width, height, window): + l, t, r, b = self.wid.GetWindowPort().GetPortBounds() + self.SetPort() + if self.barx: + self.barx.HideControl() # jvr + self.barx.MoveControl(l-1, b-(SCROLLBARWIDTH-1)) + self.barx.SizeControl((r-l)-(SCROLLBARWIDTH-3), SCROLLBARWIDTH) # jvr + if self.bary: + self.bary.HideControl() # jvr + self.bary.MoveControl(r-(SCROLLBARWIDTH-1), t-1) + self.bary.SizeControl(SCROLLBARWIDTH, (b-t)-(SCROLLBARWIDTH-3)) # jvr + if self.barx: + self.barx.ShowControl() # jvr + self.wid.ValidWindowRect((l, b - SCROLLBARWIDTH + 1, r - SCROLLBARWIDTH + 2, b)) # jvr + if self.bary: + self.bary.ShowControl() # jvr + self.wid.ValidWindowRect((r - SCROLLBARWIDTH + 1, t, r, b - SCROLLBARWIDTH + 2)) # jvr + self.wid.InvalWindowRect((r - SCROLLBARWIDTH + 1, b - SCROLLBARWIDTH + 1, r, b)) # jvr, growicon + + + def do_rawcontrolhit(self, window, control, pcode, local, event): + if control == self.barx: + which = 'x' + elif control == self.bary: + which = 'y' + else: + return 0 + if pcode in (inUpButton, inDownButton, inPageUp, inPageDown): + # We do the work for the buttons and grey area in the tracker + dummy = control.TrackControl(local, self.do_controltrack) + else: + # but the thumb is handled here + pcode = control.TrackControl(local) + if pcode == inThumb: + value = control.GetControlValue() + print 'setbars', which, value #DBG + self.scrollbar_callback(which, 'set', value) + self.updatescrollbars() + else: + print 'funny part', pcode #DBG + return 1 + + def do_controltrack(self, control, pcode): + if control == self.barx: + which = 'x' + elif control == self.bary: + which = 'y' + else: + return + + if pcode == inUpButton: + what = '-' + elif pcode == inDownButton: + what = '+' + elif pcode == inPageUp: + what = '--' + elif pcode == inPageDown: + what = '++' + else: + return + self.scrollbar_callback(which, what, None) + self.updatescrollbars() + + def updatescrollbars(self): + SetPort(self.wid) + vx, vy = self.getscrollbarvalues() + if self.barx: + if vx == None: + self.barx.HiliteControl(255) + self.barx_enabled = 0 + else: + if not self.barx_enabled: + self.barx_enabled = 1 + if self.activated: + self.barx.HiliteControl(0) + self.barx.SetControlValue(vx) + if self.bary: + if vy == None: + self.bary.HiliteControl(255) + self.bary_enabled = 0 + else: + if not self.bary_enabled: + self.bary_enabled = 1 + if self.activated: + self.bary.HiliteControl(0) + self.bary.SetControlValue(vy) + + # Auxiliary function: convert standard text/image/etc coordinate + # to something palatable as getscrollbarvalues() return + def scalebarvalue(self, absmin, absmax, curmin, curmax): + if curmin <= absmin and curmax >= absmax: + return None + if curmin <= absmin: + return 0 + if curmax >= absmax: + return 32767 + perc = float(curmin-absmin)/float(absmax-absmin) + return int(perc*32767) + + # To be overridden: + + def getscrollbarvalues(self): + return 0, 0 + + def scrollbar_callback(self, which, what, value): + print 'scroll', which, what, value + +class DialogWindow(Window): + """A modeless dialog window""" + + def open(self, resid): + self.dlg = GetNewDialog(resid, -1) + self.wid = self.dlg.GetDialogWindow() + self.do_postopen() + + def close(self): + self.do_postclose() + + def do_postclose(self): + self.dlg = None + Window.do_postclose(self) + + def do_itemhit(self, item, event): + print 'Dialog %s, item %d hit'%(self.dlg, item) + + def do_rawupdate(self, window, event): + pass + +def ostypecode(x): + "Convert a long int to the 4-character code it really is" + s = '' + for i in range(4): + x, c = divmod(x, 256) + s = chr(c) + s + return s + + +class TestApp(Application): + + "This class is used by the test() function" + + def makeusermenus(self): + self.filemenu = m = Menu(self.menubar, "File") + self.saveitem = MenuItem(m, "Save", "S", self.save) + Separator(m) + self.optionsmenu = mm = SubMenu(m, "Options") + self.opt1 = CheckItem(mm, "Arguments", "A") + self.opt2 = CheckItem(mm, "Being hit on the head lessons", (kMenuOptionModifier, "A")) + self.opt3 = CheckItem(mm, "Complaints", (kMenuOptionModifier|kMenuNoCommandModifier, "A")) + Separator(m) + self.itemeh = MenuItem(m, "Enable Help", None, self.enablehelp) + self.itemdbg = MenuItem(m, "Debug", None, self.debug) + Separator(m) + self.quititem = MenuItem(m, "Quit", "Q", self.quit) + + def save(self, *args): + print "Save" + + def quit(self, *args): + raise self + + def enablehelp(self, *args): + hm = self.gethelpmenu() + self.nohelpitem = MenuItem(hm, "There isn't any", None, self.nohelp) + + def nohelp(self, *args): + print "I told you there isn't any!" + + def debug(self, *args): + import pdb + pdb.set_trace() + + +def test(): + "Test program" + app = TestApp() + app.mainloop() + + +if __name__ == '__main__': + test() |