diff options
-rw-r--r-- | Mac/Lib/EasyDialogs.py | 110 | ||||
-rw-r--r-- | Mac/Lib/FrameWork.py | 480 |
2 files changed, 590 insertions, 0 deletions
diff --git a/Mac/Lib/EasyDialogs.py b/Mac/Lib/EasyDialogs.py new file mode 100644 index 0000000..41edd7e --- /dev/null +++ b/Mac/Lib/EasyDialogs.py @@ -0,0 +1,110 @@ +"""Easy to use dialogs. + +Message(msg) -- display a message and an OK button. +AskString(prompt, default) -- ask for a string, display OK and Cancel buttons. +AskYesNoCancel(question, default) -- display a question and Yes, No and Cancel buttons. + +More documentation in each function. +This module uses DLOG resources 256, 257 and 258. +Based upon STDWIN dialogs with the same names and functions. +""" + +from Dlg import GetNewDialog, SetIText, GetIText, ModalDialog + + +def Message(msg): + """Display a MESSAGE string. + + Return when the user clicks the OK button or presses Return. + + The MESSAGE string can be at most 255 characters long. + """ + + id = 256 + d = GetNewDialog(id, -1) + if not d: + print "Can't get DLOG resource with id =", id + return + tp, h, rect = d.GetDItem(2) + SetIText(h, msg) + while 1: + n = ModalDialog(None) + if n == 1: + return + + +def AskString(prompt, default = ""): + """Display a PROMPT string and a text entry field with a DEFAULT string. + + Return the contents of the text entry field when the user clicks the + OK button or presses Return. + Return None when the user clicks the Cancel button. + + If omitted, DEFAULT is empty. + + The PROMPT and DEFAULT strings, as well as the return value, + can be at most 255 characters long. + """ + + id = 257 + d = GetNewDialog(id, -1) + if not d: + print "Can't get DLOG resource with id =", id + return + tp, h, rect = d.GetDItem(3) + SetIText(h, prompt) + tp, h, rect = d.GetDItem(4) + SetIText(h, default) + d.SelIText(4, 0, 255) + while 1: + n = ModalDialog(None) + if n == 1: + tp, h, rect = d.GetDItem(4) + return GetIText(h) + if n == 2: return None + + +def AskYesNoCancel(question, default = 0): +## """Display a QUESTION string which can be answered with Yes or No. +## +## Return 1 when the user clicks the Yes button. +## Return 0 when the user clicks the No button. +## Return -1 when the user clicks the Cancel button. +## +## When the user presses Return, the DEFAULT value is returned. +## If omitted, this is 0 (No). +## +## The QUESTION strign ca be at most 255 characters. +## """ + + id = 258 + d = GetNewDialog(id, -1) + if not d: + print "Can't get DLOG resource with id =", id + return + # Button assignments: + # 1 = default (invisible) + # 2 = Yes + # 3 = No + # 4 = Cancel + # The question string is item 5 + tp, h, rect = d.GetDItem(5) + SetIText(h, question) + while 1: + n = ModalDialog(None) + if n == 1: return default + if n == 2: return 1 + if n == 3: return 0 + if n == 4: return -1 + + +def test(): + Message("Testing EasyDialogs.") + ok = AskYesNoCancel("Do you want to proceed?") + if ok > 0: + s = AskString("Enter your first name") + Message("Thank you,\015%s" % `s`) + + +if __name__ == '__main__': + test() diff --git a/Mac/Lib/FrameWork.py b/Mac/Lib/FrameWork.py new file mode 100644 index 0000000..3e60f70 --- /dev/null +++ b/Mac/Lib/FrameWork.py @@ -0,0 +1,480 @@ +"A sort of application framework for the Mac" + + +import MacOS +import traceback + +from addpack import addpack +addpack('Demo') +addpack('bgen') +addpack('ae') +#addpack('ctl') +addpack('dlg') +addpack('evt') +addpack('menu') +#addpack('qd') +#addpack('res') +#addpack('snd') +addpack('win') + +from AE import * +from AppleEvents import * +#from Ctl import * +#from Controls import * +from Dlg import * +from Dialogs import * +from Evt import * +from Events import * +from Menu import * +from Menus import * +#from Qd import * +#from QuickDraw import * +#from Res import * +#from Resources import * +#from Snd import * +#from Sound import * +from Win import * +from Windows import * + +import EasyDialogs + +kHighLevelEvent = 23 # Don't know what header file this should come from + + +# 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' + +# A rectangle that's bigger than the screen, +# but not so big that adding the screen size to it will cause 16-bit overflow +everywhere = (-16000, -16000, 16000, 16000) + + +class Application: + + "Application framework -- your application should be a derived class" + + def __init__(self): + self.makemenubar() + + def makemenubar(self): + self.menubar = MenuBar() + AppleMenu(self.menubar, self.getabouttext(), self.do_about) + self.makeusermenus() + + 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. + # (XXX I'm not sure if using default parameter values is the right + # way to define the mask and wait time passed to WaitNextEvent.) + + def mainloop(self, mask = everyEvent, wait = 0): + saveyield = MacOS.EnableAppswitch(self.yield) + try: + while 1: + try: + self.do1event(mask, wait) + except (Application, SystemExit): + break + finally: + MacOS.EnableAppswitch(saveyield) + + yield = -1 + + def do1event(self, mask = everyEvent, wait = 0): + event = self.getevent(mask, wait) + if event: + self.dispatch(event) + + def getevent(self, mask = everyEvent, wait = 0): + ok, event = WaitNextEvent(mask, wait) + if ok: + return event + else: + return None + + def dispatch(self, event): + (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 do_mouseDown(self, event): + (what, message, when, where, modifiers) = event + partcode, window = FindWindow(where) + if partname.has_key(partcode): + name = "do_" + partname[partcode] + else: + name = "do_%d" % partcode + try: + handler = getattr(self, name) + except AttrinuteError: + handler = self.do_unknownpartcode + handler(partcode, window, event) + + def do_inDrag(self, partcode, window, event): + window.DragWindow(where, self.draglimit) + + draglimit = everywhere + + def do_inGoAway(self, partcode, window, event): + if window.TrackGoAway(where): + self.do_close(window) + + def do_close(self, window): + print "Should close window:", window + + def do_inZoom(self, partcode, window, event): + (what, message, when, where, modifiers) = event + if window.TrackBox(where, partcode): + window.ZoomWindow(partcode, 1) + + 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_inSysWindow(self, partcode, window, event): + print "SystemClick", event, window + # SystemClick(event, window) # XXX useless, window is None + + def do_inDesk(self, partcode, window, event): + print "inDesk" + # XXX what to do with it? + + def do_inMenuBar(self, partcode, window, event): + (what, message, when, where, modifiers) = event + result = MenuSelect(where) + id = (result>>16) & 0xffff # Hi word + 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): + self.menubar.dispatch(id, item, 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 = everywhere + + def do_resize(self, width, height, window): + window.SizeWindow(width, height, 0) + self.do_postresize(width, height, window) + + def do_postresize(self, width, height, window): + SetPort(window) + InvalRect(everywhere) + + def do_inContent(self, partcode, window, event): + (what, message, when, where, modifiers) = event + local = GlobalToLocal(where) + ctltype, control = FindControl(local, window) + if ctltype and control: + pcode = control.TrackControl(local) + if pcode: + self.do_controlhit(window, control, pcode, event) + else: + print "FindControl(%s, %s) -> (%s, %s)" % \ + (local, window, ctltype, control) + + def do_controlhit(self, window, control, pcode, event): + print "control hit in", window, "on", control, "; pcode =", pcode + + def do_unknownpartcode(self, partcode, window, event): + (what, message, when, where, modifiers) = event + print "Mouse down at global:", where + print "\tUnknown part code:", partcode + + 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 modifiers & cmdKey: + if c == '.': + raise self + else: + result = MenuKey(ord(c)) + id = (result>>16) & 0xffff # Hi word + item = result & 0xffff # Lo word + if id: + self.do_rawmenu(id, item, None, event) + elif c == 'w': + w = FrontWindow() + if w: + self.do_close(w) + else: + print 'Command-W without front window' + else: + print "Command-" +`c` + else: + self.do_char(c, event) + + def do_char(self, c, event): + print "Character", `c` + + def do_updateEvt(self, event): + print "do_update", + self.printevent(event) + window = FrontWindow() # XXX This is wrong! + if window: + self.do_rawupdate(window, event) + else: + print "no window for do_updateEvt" + + def do_rawupdate(self, window, event): + print "raw update for", window + window.BeginUpdate() + self.do_update(window, event) + DrawControls(window) + window.DrawGrowIcon() + window.EndUpdate() + + def do_update(self, window, event): + EraseRect(everywhere) + + def do_kHighLevelEvent(self, event): + (what, message, when, where, modifiers) = event + print "High Level Event:", + self.printevent(event) + try: + AEProcessAppleEvent(event) + except: + print "AEProcessAppleEvent error:" + traceback.print_exc() + + def do_unknownevent(self, event): + print "Unknown 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 = self.nextid + self.nextid = id+1 + return id + + def __init__(self): + ClearMenuBar() + self.bar = GetMenuBar() + self.menus = {} + + def addmenu(self, title, after = 0): + id = self.getnextid() + m = NewMenu(id, title) + m.InsertMenu(after) + DrawMenuBar() + return id, m + + def addpopup(self, title = ''): + return self.addmenu(title, -1) + + def install(self): + self.bar.SetMenuBar() + DrawMenuBar() + + def dispatch(self, id, item, window, event): + if self.menus.has_key(id): + self.menus[id].dispatch(id, item, window, event) + else: + 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): + self.bar = bar + self.id, self.menu = self.bar.addmenu(title, after) + bar.menus[self.id] = self + self.items = [] + + 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.SetItem(item, label) # set the actual text + if shortcut: + self.menu.SetItemCmd(item, ord(shortcut)) + return item + + 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) + return sub + + def dispatch(self, id, item, window, event): + title, shortcut, callback, type = self.items[item-1] + if callback: + callback(id, item, window, event) + + +class MenuItem: + def __init__(self, menu, title, shortcut=None, callback=None, kind=None): + self.item = menu.additem(title, shortcut, callback) + +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") + self.additem(abouttext, None, aboutcallback) + self.addseparator() + self.menu.AddResMenu('DRVR') + + def dispatch(self, id, item, window, event): + if item == 1: + Menu.dispatch(self, id, item, window, event) + else: + name = self.menu.GetItem(item) + OpenDeskAcc(name) + + +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") + self.opt2 = CheckItem(mm, "Being hit on the head lessons") + self.opt3 = CheckItem(mm, "Complaints") + Separator(m) + self.quititem = MenuItem(m, "Quit", "Q", self.quit) + + def save(self, *args): + print "Save" + + def quit(self, *args): + raise self + + +def test(): + "Test program" + app = TestApp() + app.mainloop() + + +if __name__ == '__main__': + test() |