[Sugar-devel] [PATCH sugar-toolkit-gtk3] Add EventIcon/CursorInvoker similar to CanvasIcon/CanvasInvoker

Daniel Drake dsd at laptop.org
Wed Dec 14 18:47:11 EST 2011


CanvasIcon and CanvasInvoker were removed in a previous GTK3-porting commit
as they were based on hippocanvas.

However, this leaves the toolkit with some missing functionality:
there is no longer a trivial way to show an icon which can receive mouse
events and pop up a palette. Such functionality is used in various
places throughout the shell and activities.

Reimplement this functionality as EventIcon and CursorInvoker.
Instead of reimplementing much of the Icon class (like CanvasIcon did),
EventIcon opts for a more simplistic encapsulation of an Icon object.
This means trivial API changes for CanvasIcon users who must now
use the 'icon' property with the Icon API.
---
 src/sugar3/graphics/icon.py          |   70 ++++++++++++++++++++++++++++++++++
 src/sugar3/graphics/palette.py       |    2 +-
 src/sugar3/graphics/palettewindow.py |   62 ++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+), 1 deletions(-)

diff --git a/src/sugar3/graphics/icon.py b/src/sugar3/graphics/icon.py
index f6c9374..2d98f8a 100644
--- a/src/sugar3/graphics/icon.py
+++ b/src/sugar3/graphics/icon.py
@@ -29,6 +29,7 @@ from gi.repository import GObject
 from gi.repository import Gtk
 import cairo
 
+from sugar3.graphics import style
 from sugar3.graphics.xocolor import XoColor
 from sugar3.util import LRU
 
@@ -545,6 +546,75 @@ class Icon(Gtk.Image):
         type=float, setter=set_scale)
 
 
+class EventIcon(Gtk.EventBox):
+    """
+    An Icon class that provides access to mouse events and that can act as a
+    cursor-positioned palette invoker.
+    """
+
+    __gtype_name__ = 'EventIcon'
+    __gsignals__ = {
+        'activated': (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, []),
+    }
+
+    def __init__(self, **kwargs):
+        Gtk.EventBox.__init__(self)
+
+        self._icon = Icon()
+        for key, value in kwargs.iteritems():
+            self._icon.set_property(key, value)
+        self.add(self._icon)
+        self._icon.show()
+
+        from sugar3.graphics.palette import CursorInvoker
+        self._palette_invoker = CursorInvoker()
+        self._palette_invoker.attach(self)
+
+        self.modify_bg(Gtk.StateType.NORMAL, style.COLOR_WHITE.get_gdk_color())
+        self.connect('destroy', self.__destroy_cb)
+
+    def __destroy_cb(self, icon):
+        if self._palette_invoker is not None:
+            self._palette_invoker.detach()
+
+    def do_button_press_event(self, event):
+        if event.button == 1:
+            self.emit('activated')
+            return True
+        else:
+            return False
+
+    def get_icon(self):
+        return self._icon
+
+    icon = GObject.property(
+        type=object, getter=get_icon)
+
+    def get_palette(self):
+        return self._palette_invoker.palette
+
+    def set_palette(self, palette):
+        self._palette_invoker.palette = palette
+
+    palette = GObject.property(
+        type=object, setter=set_palette, getter=get_palette)
+
+    def get_palette_invoker(self):
+        return self._palette_invoker
+
+    def set_palette_invoker(self, palette_invoker):
+        self._palette_invoker.detach()
+        self._palette_invoker = palette_invoker
+
+    palette_invoker = GObject.property(
+        type=object, setter=set_palette_invoker, getter=get_palette_invoker)
+
+    def set_tooltip(self, text):
+        from sugar3.graphics.palette import Palette
+
+        self.set_palette(Palette(text))
+
+
 class CellRendererIcon(Gtk.CellRenderer):
 
     __gtype_name__ = 'SugarCellRendererIcon'
diff --git a/src/sugar3/graphics/palette.py b/src/sugar3/graphics/palette.py
index b23a28d..ee76674 100644
--- a/src/sugar3/graphics/palette.py
+++ b/src/sugar3/graphics/palette.py
@@ -35,7 +35,7 @@ from gi.repository import SugarExt
 # DEPRECATED
 # Import these for backwards compatibility
 from sugar3.graphics.palettewindow import MouseSpeedDetector, Invoker, \
-        WidgetInvoker, CanvasInvoker, ToolInvoker, CellRendererInvoker
+        WidgetInvoker, CursorInvoker, ToolInvoker, CellRendererInvoker
 
 
 class Palette(PaletteWindow):
diff --git a/src/sugar3/graphics/palettewindow.py b/src/sugar3/graphics/palettewindow.py
index baf96e3..562f1d5 100644
--- a/src/sugar3/graphics/palettewindow.py
+++ b/src/sugar3/graphics/palettewindow.py
@@ -788,6 +788,68 @@ class WidgetInvoker(Invoker):
     widget = GObject.property(type=object, getter=_get_widget, setter=None)
 
 
+class CursorInvoker(Invoker):
+
+    def __init__(self, parent=None):
+        Invoker.__init__(self)
+
+        self._position_hint = self.AT_CURSOR
+        self._enter_hid = None
+        self._leave_hid = None
+        self._release_hid = None
+        self._item = None
+
+        if parent:
+            self.attach(parent)
+
+    def attach(self, parent):
+        Invoker.attach(self, parent)
+
+        self._item = parent
+        self._enter_hid = self._item.connect('enter-notify-event',
+                                             self.__enter_notify_event_cb)
+        self._leave_hid = self._item.connect('leave-notify-event',
+                                             self.__leave_notify_event_cb)
+        self._release_hid = self._item.connect('button-release-event',
+                                               self.__button_release_event_cb)
+
+    def detach(self):
+        Invoker.detach(self)
+        self._item.disconnect(self._enter_hid)
+        self._item.disconnect(self._leave_hid)
+        self._item.disconnect(self._release_hid)
+
+    def get_default_position(self):
+        return self.AT_CURSOR
+
+    def get_rect(self):
+        window = self._item.get_window()
+        allocation = self._item.get_allocation()
+        rect = Gdk.Rectangle()
+        rect.x, rect.y = window.get_root_coords(allocation.x, allocation.y)
+        rect.width = allocation.width
+        rect.height = allocation.height
+        return rect
+
+    def __enter_notify_event_cb(self, button, event):
+        self.notify_mouse_enter()
+        return False
+
+    def __leave_notify_event_cb(self, button, event):
+        self.notify_mouse_leave()
+        return False
+
+    def __button_release_event_cb(self, button, event):
+        if event.button == 3:
+            self.notify_right_click()
+            return True
+        else:
+            return False
+
+    def get_toplevel(self):
+        return self._item.get_toplevel()
+
+
 class ToolInvoker(WidgetInvoker):
 
     def __init__(self, parent=None):
-- 
1.7.7.4



More information about the Sugar-devel mailing list