# # Python GUI - Components - Gtk # from gi.repository import Gtk from gi.repository import Gdk import GUI.Globals from GUI.Geometry import sub_pt from GUI.GComponents import Component as GComponent from GUI.Events import Event, _gtk_key_event_of_interest _gdk_events_of_interest = ( Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.BUTTON_MOTION_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK | Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK | 0 ) _gtk_widget_to_component = {} _gtk_last_keyval_down = None #------------------------------------------------------------------------------ class Component(GComponent): _pass_key_events_to_platform = True def __init__(self, _gtk_outer, _gtk_inner = None, _gtk_focus = None, _gtk_input = None, **kwds): self._position = (0, 0) req = _gtk_outer.size_request() self._size = (req.width, req.height) _gtk_inner = _gtk_inner or _gtk_outer self._gtk_outer_widget = _gtk_outer self._gtk_inner_widget = _gtk_inner self._gtk_focus_widget = _gtk_focus _gtk_widget_to_component[_gtk_outer] = self self._gtk_connect_input_events(_gtk_input or _gtk_inner) if _gtk_focus: _gtk_focus.set_property('can-focus', True) self._gtk_connect(_gtk_focus, 'focus-in-event', self._gtk_focus_in) GComponent.__init__(self, **kwds) def destroy(self): gtk_widget = self._gtk_outer_widget if gtk_widget in _gtk_widget_to_component: del _gtk_widget_to_component[gtk_widget] GComponent.destroy(self) # # Properties # def set_width(self, v): w, h = self.size self.size = (v, h) def set_height(self, v): w, h = self.size self.size = (w, v) def get_position(self): return self._position def set_position(self, v): self._position = v widget = self._gtk_outer_widget parent = widget.get_parent() if parent: parent.move(widget, *v) def get_size(self): return self._size def set_size(self, new_size): w0, h0 = self._size w1, h1 = new_size self._gtk_outer_widget.set_size_request(max(int(w1), 1), max(int(h1), 1)) self._size = new_size if w0 != w1 or h0 != h1: self._resized((w1 - w0, h1 - h0)) def get_bounds(self): x, y = self._position w, h = self.size return (x, y, x + w, y + h) def set_bounds(self, (l, t, r, b)): self.position = (l, t) self.size = (r - l, b - t) # def get_visible(self): # return self._gtk_outer_widget.get_property('visible') # # def set_visible(self, v): # self._gtk_outer_widget.set_property('visible', v) # # Message dispatching # def become_target(self): gtk_focus = self._gtk_focus_widget if gtk_focus: gtk_focus.grab_focus() else: raise ValueError("%r cannot be targeted" % self) # def current_target(self): # """Find the current target object within the Window containing # this component. If the component is not contained in a Window, # the result is undefined.""" # target = _gtk_find_component(self._gtk_outer_widget.get_focus()) # if not target: # target = self.window # return target def is_target(self): """Return true if this is the current target within the containing Window. If the component is not contained in a Window, the result is undefined.""" gtk_focus = self._gtk_focus_widget if gtk_focus: return gtk_focus.get_property('has-focus') else: return False # # Internal # def _gtk_connect(self, gtk_widget, signal, handler): def catch(widget, *args): try: handler(*args) except: _gtk_exception_in_signal_handler() gtk_widget.connect(signal, lambda widget, *args: handler(*args)) def _gtk_connect_after(self, gtk_widget, signal, handler): def catch(widget, *args): try: handler(*args) except: _gtk_exception_in_signal_handler() gtk_widget.connect_after(signal, lambda widget, *args: handler(*args)) def _gtk_focus_in(self, gtk_event): window = self.window if window: old_target = window._target window._target = self if old_target and old_target is not self: old_target._untargeted() self._targeted() def _targeted(self): pass def _untargeted(self): pass def _gtk_connect_input_events(self, gtk_widget): self._last_mouse_down_time = 0 self._click_count = 0 gtk_widget.add_events(_gdk_events_of_interest) self._gtk_connect(gtk_widget, 'button-press-event', self._gtk_button_press_event_signal) self._gtk_connect(gtk_widget, 'motion-notify-event', self._gtk_motion_notify_event_signal) self._gtk_connect(gtk_widget, 'button-release-event', self._gtk_button_release_event_signal) self._gtk_connect(gtk_widget, 'enter-notify-event', self._gtk_enter_leave_event_signal) self._gtk_connect(gtk_widget, 'leave-notify-event', self._gtk_enter_leave_event_signal) self._gtk_connect(gtk_widget, 'key-press-event', self._handle_gtk_key_event) self._gtk_connect(gtk_widget, 'key-release-event', self._handle_gtk_key_event) def _gtk_button_press_event_signal(self, gtk_event): if gtk_event.type == Gdk.EventType.BUTTON_PRESS: # don't want 2BUTTON or 3BUTTON event = Event._from_gtk_mouse_event(gtk_event) last_time = self._last_mouse_down_time this_time = event.time num_clicks = self._click_count if this_time - last_time <= 0.25: num_clicks += 1 else: num_clicks = 1 event.num_clicks = num_clicks self._click_count = num_clicks self._last_mouse_down_time = this_time #print "Component._gtk_button_press_event_signal:" ### #print event ### return self._event_custom_handled(event) def _gtk_motion_notify_event_signal(self, gtk_event): event = Event._from_gtk_mouse_event(gtk_event) self._mouse_event = event return self._event_custom_handled(event) def _gtk_button_release_event_signal(self, gtk_event): event = Event._from_gtk_mouse_event(gtk_event) self._mouse_event = event return self._event_custom_handled(event) def _gtk_enter_leave_event_signal(self, gtk_event): #print "Component._gtk_enter_leave_event_signal:" ### event = Event._from_gtk_mouse_event(gtk_event) return self._event_custom_handled(event) def _handle_gtk_key_event(self, gtk_event): """Convert a Gtk key-press or key-release event into an Event object and pass it up the message path.""" #print "Component._handle_gtk_key_event for", self ### global _gtk_last_keyval_down if _gtk_key_event_of_interest(gtk_event): event = Event._from_gtk_key_event(gtk_event) if event.kind == 'key_down': this_keyval = gtk_event.keyval if _gtk_last_keyval_down == this_keyval: event.auto = 1 _gtk_last_keyval_down = this_keyval else: _gtk_last_keyval_down = None #if event.kind == 'key_down': ### # print event ### return self._event_custom_handled(event) #------------------------------------------------------------------------------ def _gtk_find_component(gtk_widget): while gtk_widget: component = _gtk_widget_to_component.get(gtk_widget) if component: return component gtk_widget = gtk_widget.get_parent() return None def _gtk_exception_in_signal_handler(): print >>sys.stderr, "---------- Exception in gtk signal handler ----------" traceback.print_exc()