|
From: Kevin A. <ka...@us...> - 2004-04-30 23:55:59
|
Update of /cvsroot/pythoncard/PythonCard/components In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8284/components Modified Files: button.py Log Message: transition code to new style event binding and dispatch I don't want to lose this code, so I'm "backing up" to cvs :) note that ImageButton which relies on Button binding has been broken since earlier this week when we started the new style tests Index: button.py =================================================================== RCS file: /cvsroot/pythoncard/PythonCard/components/button.py,v retrieving revision 1.25 retrieving revision 1.26 diff -C2 -d -r1.25 -r1.26 *** button.py 27 Apr 2004 02:43:33 -0000 1.25 --- button.py 30 Apr 2004 23:55:49 -0000 1.26 *************** *** 8,12 **** from PythonCard import event, widget ! ButtonEvents = [event.ButtonMouseClickEvent] class ButtonSpec(widget.WidgetSpec): --- 8,17 ---- from PythonCard import event, widget ! class ButtonMouseClickEvent(event.MouseClickEvent): ! binding = wx.EVT_BUTTON ! id = wx.wxEVT_COMMAND_BUTTON_CLICKED ! ! ButtonEvents = (ButtonMouseClickEvent,) ! #ButtonEvents = [ButtonMouseClickEvent] class ButtonSpec(widget.WidgetSpec): *************** *** 14,18 **** # KEA 2004-04-26 # test to use new event classes ! events = ButtonEvents ## events = [event.MouseClickEvent] attributes = { --- 19,24 ---- # KEA 2004-04-26 # test to use new event classes ! events = list(ButtonEvents) ! #events = ButtonEvents ## events = [event.MouseClickEvent] attributes = { *************** *** 47,52 **** self._setDefault(self._resource.default) ! adapter = ButtonEventBinding(self) ! adapter.bindEvents() def _getDefault(self): --- 53,59 ---- self._setDefault(self._resource.default) ! #adapter = ButtonEventBinding(self) ! #adapter.bindEvents() ! self._bindEvents() def _getDefault(self): *************** *** 74,77 **** --- 81,305 ---- pass + def _bindEvents(self): + # shouldn't components be subclasses of Scriptable? + # components would have their own handlers but when + # looking for a handler match it will search the parents + # for now just grab handlers from the background + background = self.GetParent().GetParent() + + # where should this check go? + # should we just set a "global" in the app instance such as + # self.stack.app.bindUnusedEvents + # this kind of thing isn't going to work for Rowland's compound + # components + if background.stack.app._showDebugMenu: + bindUnusedEvents = True + else: + bindUnusedEvents = False + + # helper variable to simplify test for whether to bind InsteadOfTypeEvents + boundEvents = {} + + self.eventIdToHandler = {} + self.wxEventIdMap = {} + + if 0: + print "\nBINDING...", self.name + + for eventClass in event.WIDGET_EVENTS + ButtonEvents: + #for eventClass in ButtonEvents: + # need to figure out a way to avoid the need + # for this id to class mapping which is used in _dispatch below + self.wxEventIdMap[eventClass.id] = eventClass + # command handler overrides normal mouseClick or select handler + # so dispatch will automatically dispatch to the command handler + # by looking up the handler this way + # it also means that if there is a command association with this component + # then the regular mouseClick or select handler will never be bound, just ignored + if issubclass(eventClass, event.CommandTypeEvent) and self.command: + handler = background.findHandler('on_' + self.command + '_command') + if not handler: + handler = background.findHandler('on_' + self.name + '_' + eventClass.name) + else: + handler = background.findHandler('on_' + self.name + '_' + eventClass.name) + if not handler: + handler = background.findHandler('on_' + eventClass.name) + if handler or bindUnusedEvents: + # only bind events that have an event handler + # in this scenario unused events are never bound + # which is more efficient, but the Message Watcher needs + # to be changed + # alternatively we can bind everything and then in _dispatch + # if there isn't a match in eventIdToHandler then we know + # the event isn't used and we can set used to False + # the complication would be that we probably have to have to + # always call Skip() which may or may not be a hassle with components + + # this doesn't bind command events + # they would be of the form on_somename_command + # or perhaps on_command but I don't think we would want + # to support that + # the event binding would be specific to a component + # since on dispatch command overrides something like mouseClickEvent + # but the name of the command is not related to the component + # need to look at whether self.command has a value and then bind + # with ButtonMouseClickEvent.binding if that isn't already bound + # then in dispatch have to check again I think + + # need to avoid double binding + # also binding shouldn't be order-specific + # so how to avoid binding mouseDrag to _dispatch + # if mouseMove is already bound or if binding mouseMove + # not rebinding if mouseDrag is already bound + # perhaps MouseDragEvent keeps a reference to MouseMoveEvent + # and that is inserted into boundEvents, then we check boundEvents + # prior to rebinding? + if not boundEvents.get(eventClass.binding, None): + self.Bind(eventClass.binding, self._dispatch) + boundEvents[eventClass.binding] = eventClass.name + if handler: + if 0: + print " binding", self.name, eventClass.name, handler._name, eventClass.id + self.eventIdToHandler[eventClass.id] = handler + + if 0: + print "\n boundEvents:" + for name in boundEvents.values(): + print " ", name + print "\n\n" + print "\n self.eventIdToHandler:" + for id in self.eventIdToHandler: + print " ", id, self.eventIdToHandler[id]._function + print "\n\n" + boundEvents = None + + # this is pretty generic, but Button doesn't have any specific + # handling that is required so I need to do the same kind of code + # for TextField and see what the special handling for gainFocus, + # loseFocus, closeField will look like + # it probably won't need special handling for the key events + def _dispatch(self, aWxEvent): + eventType = aWxEvent.GetEventType() + + eventName = None + + if eventType == wx.wxEVT_TIMER: + aWxEvent.interval = aWxEvent.GetInterval() + # wxPython 2.5.1.5 workaround + # for some reason wx.TimerEvent does not contain the event target + # so we have to set it ourselves + aWxEvent.target = aWxEvent.eventObject = self + else: + try: + # all events should have GetEventObject() + # except of course for wx.TimerEvent above + # KEA 2004-04-25 + # should we remove this redundant identifier? + aWxEvent.target = aWxEvent.eventObject = self + except: + pass + # Each of these could check the event class like + # wxListEvent and wxTreeEvent above. + try: + # mouse and key events + aWxEvent.position = tuple(aWxEvent.GetPosition()) + aWxEvent.x = aWxEvent.GetX() + aWxEvent.y = aWxEvent.GetY() + aWxEvent.altDown = aWxEvent.AltDown() + aWxEvent.controlDown = aWxEvent.ControlDown() + aWxEvent.shiftDown = aWxEvent.ShiftDown() + except: + pass + try: + # key events + aWxEvent.keyCode = aWxEvent.GetKeyCode() + except: + pass + if issubclass(self.wxEventIdMap[eventType], event.CommandTypeEvent): + # could be command, so need to report the name + # for the handler if it exists + if self.command: + eventName = 'command' + elif eventType == event.MouseMoveEvent.id: + # check to see if this is a mouseDrag + if aWxEvent.Dragging(): + eventType = event.MouseDragEvent.id + # don't need this if all event types have unique ids + #eventName = event.MouseDragEvent.name + + # the component-specific helper attributes below + # should be handled in the relevant component _dispatch + # not the generic one + """ + if eventType in [wx.wxEVT_COMMAND_LIST_KEY_DOWN, + wx.wxEVT_COMMAND_TREE_KEY_DOWN]: + try: + # key events are different for wxTreeCtrl and wxListCtrl + aWxEvent.keyCode = aWxEvent.GetCode() + except: + pass + try: + # wxListEvent doesn't have GetKeyEvent for some reason + keyEvent = aWxEvent.GetKeyEvent() + aWxEvent.altDown = keyEvent.AltDown() + aWxEvent.controlDown = keyEvent.ControlDown() + aWxEvent.shiftDown = keyEvent.ShiftDown() + except: + pass + elif eventType in [wx.wxEVT_COMMAND_TREE_BEGIN_DRAG, \ + wx.wxEVT_COMMAND_TREE_BEGIN_RDRAG, \ + wx.wxEVT_COMMAND_TREE_END_DRAG, \ + wx.wxEVT_COMMAND_LIST_BEGIN_DRAG, \ + wx.wxEVT_COMMAND_LIST_BEGIN_RDRAG, \ + wx.wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, \ + wx.wxEVT_COMMAND_LIST_COL_DRAGGING, \ + wx.wxEVT_COMMAND_LIST_COL_END_DRAG]: + try: + # The mouse position during a drag event + # there doesn't appear to be a way of getting the + # state of the shift, alt, and control keys + # during a mouse drag. + aWxEvent.position = tuple(aWxEvent.GetPoint()) + aWxEvent.x = aWxEvent.position[0] + aWxEvent.y = aWxEvent.position[1] + except: + pass + """ + + if not eventName: + eventName = self.wxEventIdMap[eventType].name + + # it shouldn't be possible to be in _dispatch for an event + # that wasn't bound above, but just in case... + handler = self.eventIdToHandler.get(eventType, None) + if handler: + event.EventQueue()._impl.eventOccurred2(eventName, self.name, True) + if 0: + print "dispatching", handler._name + # make a lowercase alias + aWxEvent.skip = aWxEvent.Skip + + # the event handlers are part of the Background so + # we have to have a reference to call the handler below + background = self.GetParent().GetParent() + + # this is what is in event.py + # aHandler.getFunction()( aOwner, self.getSource(), self ) + handler.getFunction()(background, aWxEvent) + + # do we have to clean up this alias? + aWxEvent.skip = None + # how about this local reference to handler? + handler = None + background = None + else: + event.EventQueue()._impl.eventOccurred2(eventName, self.name, False) + # hopefully this is all we need to do for "unused events" + aWxEvent.Skip() + + # cleanup + aWxEvent.target = aWxEvent.eventObject = None + + default = property(_getDefault, _setDefault) label = property(wx.Button.GetLabel, wx.Button.SetLabel) |