From e77d27c246b060c8c7e49031f18ec8c66edb7d15 Mon Sep 17 00:00:00 2001 From: Jeff Armstrong Date: Wed, 20 Jul 2011 22:30:10 -0400 Subject: Event handling added to Python wrappers. GEM constants added. Fixed minor typo in dynload_mint. --- gem/aes.py | 283 ++++++++++++++++++++++++++++++++++++++++++------------- gem/constants.py | 146 ++++++++++++++++++++++++++++ 2 files changed, 365 insertions(+), 64 deletions(-) create mode 100644 gem/constants.py (limited to 'gem') diff --git a/gem/aes.py b/gem/aes.py index ac29463..71f78dc 100644 --- a/gem/aes.py +++ b/gem/aes.py @@ -1,64 +1,219 @@ -import _gem - -from error import GEMError - -def alert(message,type=None,buttons=('Ok',),default=None): - """Displays a generic GEM alert box with the specified - message. The type of box may also be specified as one - of ('none', 'exclamation', 'question', 'stop', 'info', - 'disk', 'bomb'). The buttons parameter can contain a - tuple or list of button texts (up to 3, as limited by - GEM.""" - - alert_types = ['none', 'exclamation', 'question', - 'stop', 'info', 'disk', 'bomb'] - try: - internal_type = alert_type.index(type.lower()) - except ValueError: - raise GEMError('Unknown alert box type') - except AttributeError: - if type is None: - internal_type = 0 - else: - internal_type = type - - if default is None: - default = 0 - elif type(default) is str: - try: - default = buttons.index(default) - except ValueError: - raise GEMError('Could not locate default button') - - bstring = '' - if len(buttons) > 3: - buttons = buttons[0:3] - for button in buttons: - if len(button) > 10: - button = button[0:10] - bstring = bstring + button + '|' - bstring = bstring[:-1] - - astring = "[{0}][{1}][{2}]".format(repr(internal_type), - message, bstring) - - return _gem.form_alert(default, astring) - -class Window: - def __init__(self, type): - - self.id = _gem.wind_create(type,(0,0,10,10)) - - -class Application: - - def __init__(self): - self.id = _gem.appl_init() - if self.id == -1: - raise GEMError("The application failed to initialize") - - self.windows = [] - - def destroy(self): - _gem.appl_exit(self.id) - \ No newline at end of file +import _gem + +from error import GEMError +from constants import * + +def alert(message,type=None,buttons=('Ok',),default=None): + """Displays a generic GEM alert box with the specified + message. The type of box may also be specified as one + of ('none', 'exclamation', 'question', 'stop', 'info', + 'disk', 'bomb'). The buttons parameter can contain a + tuple or list of button texts (up to 3, as limited by + GEM.""" + + alert_types = ['none', 'exclamation', 'question', + 'stop', 'info', 'disk', 'bomb'] + try: + internal_type = alert_type.index(type.lower()) + except ValueError: + raise GEMError('Unknown alert box type') + except AttributeError: + if type is None: + internal_type = 0 + else: + internal_type = type + + if default is None: + default = 0 + elif type(default) is str: + try: + default = buttons.index(default) + except ValueError: + raise GEMError('Could not locate default button') + + bstring = '' + if len(buttons) > 3: + buttons = buttons[0:3] + for button in buttons: + if len(button) > 10: + button = button[0:10] + bstring = bstring + button + '|' + bstring = bstring[:-1] + + astring = "[{0}][{1}][{2}]".format(repr(internal_type), + message, bstring) + + return _gem.form_alert(default, astring) + +def window_update(action): + """Issues a 'wind_update()' call to the AES with the specified + argument. The action argument must be END_UPDATE, BEG_UPDATE, + END_MCTRL, or BEG_MCTRL.""" + _gem.wind_update(action) + +class Window: + """A class wrapping GEM windows and their functionality""" + + def __init__(self, type=NAME|FULLER|CLOSER|SIZER): + """Creates (but does not show) a window""" + self.id = _gem.wind_create(type,(0,0,10,10)) + + def open(self,rect): + """Opens a window using the the specified rectangle (x,y,w,h)""" + _gem.wind_open(self.id, rect) + + def close(self): + """Closes (but does not destroy) a window""" + _gem.wind_close(self.id) + + def destroy(self): + """Deletes an existing GEM window""" + _gem.wind_delete(self.id) + + def set_name(self,name): + """Sets the name of a window""" + _gem.wind_set(self.id,WF_NAME,name) + + def begin_update(self): + window_update(BEG_UPDATE) + + def end_update(self): + window_update(END_UPDATE) + +class Event: + def __init__(self): + pass + + def process(self): + pass + +class MouseButtonEvent(Event): + """A base mouse button event class""" + def __init__(self, clicks=1, mask=MB_LEFT, state=0): + Event.__init__(self) + self.clicks = clicks + self.mask = mask + self.requested_state = state + + self.returned_button = None + self.returned_state = None + self.returned_clicks = None + self.position = None + +class MouseMovementEvent(Event): + def __init__(self): + Event.__init__(self) + raise RuntimeError("Not yet implemented") + +class TimerEvent(Event): + def __init__(self, length=1000): + Event.__init__(self) + self.length = length + +class KeyboardEvent(Event): + def __init__(self): + Event.__init__(self) + + self.keycode = None + +class MessageEvent(Event): + def __init__(self): + Event.__init__(self) + + self.message = None + +class Application: + + def __init__(self): + """Initializes the GEM application""" + self.id = _gem.appl_init() + if self.id == -1: + raise GEMError("The application failed to initialize") + + self.windows = [] + self.resource = False + + self.message_event = None + self.button_event = None + self.keyboard_event = None + self.mouse_event = None + self.timer_event = None + + self.event_processing = False + + def destroy(self): + """Destroys the application""" + _gem.appl_exit(self.id) + + def load_resource(self,file): + """Loads a resource file into the application.""" + try: + _gem.rsrc_load(file) + self.resource = True + except: + self.resource = False + raise GEMError("Could not load the resource file {0}".format(file)) + + def get_resource_address(self,type,index): + """Retrieves the address of a resource element in a Python capsule. + The returned object should never be directly modified.""" + if not self.resource: + raise GEMError("A resource has not yet be loaded") + + return _gem.rsrc.gaddr(type,index) + + def event_loop(self): + """Executes the GEM event loop, watching for events specified + by the event attributes of the Application object.""" + + self.event_processing = True + while self.event_processing: + + events = 0 + kwdict = dict() + if self.message_event is not None: + events = events | MU_MESAG + + if self.button_event is not None: + events = events | MU_BUTTON + kwdict['mouse_buttons'] = (self.button_event.clicks, + self.button_event.mask, + self.button_event.state) + + if self.timer_event is not None: + events = events | MU_TIMER + kwdict['timer'] = self.timer_event.length + + if self.keyboard_event is not None: + events = events | MU_KEYBD + + if self.mouse_event is not None: + self.event_processing = False + raise RuntimeError("Not yet implemented") + events = events | MU_M1 | MU_M2 | MU_WHEEL | MU_MX + + if events == 0: + self.event_processing = False + raise GEMError("No event callbacks have been specified") + + ret = _gem.evnt_multi(events,**kwdict) + + if ret['events'] & MU_MESAG: + self.message_event.message = ret['message'] + self.message_event.process() + + if ret['events'] & MU_BUTTON: + self.button_event.position = ret['mouse_position'] + self.button_event.returned_button = ret['mouse_button'][0] + self.button_event.returned_state = ret['mouse_button'][1] + self.button_event.returned_clicks = ret['mouse_button'][2] + self.button_event.process() + + if ret['events'] & MU_TIMER: + self.timer_event.process() + + if ret['events'] & MU_KEYBD: + self.keyboard_event.keycode = ret['key'] + self.keyboard_event.process() + + \ No newline at end of file diff --git a/gem/constants.py b/gem/constants.py new file mode 100644 index 0000000..0b48d93 --- /dev/null +++ b/gem/constants.py @@ -0,0 +1,146 @@ + +# Window Constants +NAME = 0x0001 # Title-bar +CLOSER = 0x0002 # Close-box +FULLER = 0x0004 # Fuller-box +MOVER = 0x0008 # Window may be moved by user +INFO = 0x0010 # Info-line +SIZER = 0x0020 # Sizer-box +UPARROW = 0x0040 # Up-arrow +DNARROW = 0x0080 # Down-arrow +VSLIDE = 0x0100 # Vertical slider +LFARROW = 0x0200 # Left arrow +RTARROW = 0x0400 # Right arrow +HSLIDE = 0x0800 # Horizontal slider +HOTCLOSEBOX = 0x1000 # Close-box with auto-repeat +MENUBAR = 0x1000 # Menu bar (XaAES) +BACKDROP = 0x2000 # Background-box +ICONIFIER = 0x4000 # Iconify-button +BORDER = 0x8000 # Border sizing + +# Window Update Values +END_UPDATE = 0 +BEG_UPDATE = 1 +END_MCTRL = 2 +BEG_MCTRL = 3 + +# Window Set/Get Messages +WF_KIND = 1 +WF_NAME = 2 +WF_INFO = 3 +WF_WORKXYWH = 4 +WF_CURRXYWH = 5 +WF_PREVXYWH = 6 +WF_FULLXYWH = 7 +WF_HSLIDE = 8 +WF_VSLIDE = 9 +WF_TOP = 10 +WF_FIRSTXYWH = 11 +WF_NEXTXYWH = 12 +WF_IGNORE = 13 +WF_FIRSTAREAXYWH = 13 +WF_NEWDESK = 14 +WF_HSLSIZE = 15 +WF_VSLSIZE = 16 +WF_SCREEN = 17 +WF_COLOR = 18 +WF_ATTRB = 18 +WF_DCOLOR = 19 +WF_SIZETOP = 19 +WF_OWNER = 20 +WF_BEVENT = 24 +WF_BOTTOM = 25 +WF_ICONIFY = 26 +WF_UNICONIFY = 27 +WF_UNICONIFYXYWH = 28 +WF_TOOLBAR = 30 +WF_FTOOLBAR = 31 +WF_NTOOLBAR = 32 +WF_MENU = 33 +WF_WHEEL = 40 +WF_OPTS = 41 +WF_CALCF2W = 42 +WF_CALCW2F = 43 +WF_CALCF2U = 44 +WF_CALCU2F = 45 +WF_MAXWORKXYWH = 46 +WF_M_BACKDROP = 100 +WF_M_OWNER = 101 +WF_M_WINDLIST = 102 +WF_MINXYWH = 103 +WF_INFOXYWH = 104 +WF_WIDGETS = 200 +WF_USER_POINTER = 230 +WF_WIND_ATTACH = 231 +WF_TOPMOST = 232 +WF_OBFLAG = 1001 +WF_OBTYPE = 1002 +WF_OBSPEC = 1003 +X_WF_MENU = 4352 +X_WF_DIALOG = 4608 +X_WF_DIALWID = 4864 +X_WF_DIALHT = 5120 +X_WF_DFLTDESK = 5376 +X_WF_MINMAX = 5632 +X_WF_HSPLIT = 5888 +X_WF_VSPLIT = 6144 +X_WF_SPLMIN = 6400 +X_WF_HSLIDE2 = 6656 +X_WF_VSLIDE2 = 6912 +X_WF_HSLSIZE2 = 7168 +X_WF_VSLSIZE2 = 7424 +X_WF_DIALFLGS = 7680 +X_WF_OBJHAND = 7936 +X_WF_DIALEDIT = 8192 +X_WF_DCOLSTAT = 8448 +WF_WINX = 22360 +WF_WINXCFG = 22361 +WF_DDELAY = 22362 +WF_SHADE = 22365 +WF_STACK = 22366 +WF_TOPALL = 22367 +WF_BOTTOMALL = 22368 +XA = 22593 + +# Resource Constants +R_TREE = 0  +R_OBJECT = 1  +R_TEDINFO = 2  +R_ICONBLK = 3  +R_BITBLK = 4  +R_STRING = 5  +R_IMAGEDATA = 6  +R_OBSPEC = 7  +R_TEPTEXT = 8  +R_TEPTMPLT = 9  +R_TEPVALID = 10 +R_IBPMASK = 11 +R_IBPDATA = 12 +R_IBPTEXT = 13 +R_BIPDATA = 14 +R_FRSTR = 15 +R_FRIMG = 16 + +# Event types +MU_KEYBD = 0x0001 +MU_BUTTON = 0x0002 +MU_M1 = 0x0004 +MU_M2 = 0x0008 +MU_MESAG = 0x0010 +MU_TIMER = 0x0020 +MU_WHEEL = 0x0040 +MU_MX = 0x0080 +MU_KEYBD4 = 0x0100 +MU_NORM_KEYBD = 0x0100 +MU_DYNAMIC_KEYBD = 0x0200 +X_MU_DIALOG = 0x4000 + +# Mouse Button Masks +MB_LEFT = 0x0001 +MB_RIGHT = 0x0002 +MB_CENTER = 0x0004 + +MB_KRSHIFT = 0x0001 +MB_KLSHIFT = 0x0002 +MB_KCONTROL = 0x0004 +MB_KALT = 0x0008 \ No newline at end of file -- cgit v1.2.3