[gnome-clocks] First cut at selection mode



commit 7b6ef4bfa28225f400c0c8730e239ddbf671e6bd
Author: Paolo Borelli <pborelli gnome org>
Date:   Sun Aug 19 10:06:50 2012 +0200

    First cut at selection mode
    
    I did not import libgd, since it would be painful (switching build
    system, compile C, add introspection etc) and since it does more than we
    need (switching list view and icon view etc). Fow now I somply ported
    the selection cell renderer to python, it is just ~100 lines of code.

 gnomeclocks/app.py     |    6 ++
 gnomeclocks/clocks.py  |   96 +++++++++++++++++-------------------
 gnomeclocks/widgets.py |  128 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 179 insertions(+), 51 deletions(-)
---
diff --git a/gnomeclocks/app.py b/gnomeclocks/app.py
index 0d290ca..a56e67a 100644
--- a/gnomeclocks/app.py
+++ b/gnomeclocks/app.py
@@ -338,6 +338,12 @@ class ClocksToolbar(Gtk.Toolbar):
         self.selection_toolbar.set_visible(selection_mode)
         self.set_visible(not selection_mode)
 
+        active_view = None
+        for view in self.views:
+            if view.button.get_active():
+                active_view = view
+        active_view.set_selection_mode(selection_mode)
+
     def _delete_clock(self, button):
         pass
 
diff --git a/gnomeclocks/clocks.py b/gnomeclocks/clocks.py
index a1a44dc..f9d392b 100644
--- a/gnomeclocks/clocks.py
+++ b/gnomeclocks/clocks.py
@@ -20,7 +20,8 @@ from gi.repository import Gtk, GObject, Gio
 from gi.repository.GdkPixbuf import Pixbuf
 
 from widgets import NewWorldClockDialog, AlarmDialog
-from widgets import DigitalClock, AlarmWidget, EmptyPlaceholder
+from widgets import DigitalClock, AlarmWidget, SelectableIconView, EmptyPlaceholder
+from widgets import TogglePixbufRenderer
 from storage import worldclockstorage
 from utils import SystemSettings, Alert
 
@@ -80,47 +81,39 @@ class Clock(Gtk.EventBox):
 class World(Clock):
     def __init__(self):
         Clock.__init__(self, _("World"), True, True)
-        self.addButton = None
 
-        self.liststore = liststore = Gtk.ListStore(Pixbuf, str,
-                                                   GObject.TYPE_PYOBJECT)
-        self.iconview = iconview = Gtk.IconView.new()
+        self.liststore = Gtk.ListStore(bool,
+                                       Pixbuf,
+                                       str,
+                                       GObject.TYPE_PYOBJECT)
+        self.iconview = SelectableIconView(self.liststore, 0, 1, 2)
 
         self.empty_view = EmptyPlaceholder(
                 "document-open-recent-symbolic",
                  _("Select <b>New</b> to add a world clock"))
 
-        iconview.set_model(liststore)
-        iconview.set_spacing(3)
-        iconview.set_pixbuf_column(0)
-        iconview.get_style_context().add_class('content-view')
+        self.iconview.set_spacing(3)
+        self.iconview.get_style_context().add_class('content-view')
 
-        renderer_text = Gtk.CellRendererText()
-        renderer_text.set_alignment(0.5, 0.5)
-        iconview.pack_start(renderer_text, True)
-        iconview.add_attribute(renderer_text, "markup", 1)
-
-        self.scrolledwindow = scrolledwindow = Gtk.ScrolledWindow()
-        scrolledwindow.add(iconview)
+        self.scrolledwindow = Gtk.ScrolledWindow()
+        self.scrolledwindow.add(self.iconview)
 
-        iconview.connect("selection-changed", self._on_selection_changed)
+        self.iconview.connect("item-activated", self._on_item_activated)
+        self.iconview.connect("selection-changed", self._on_selection_changed)
 
         self.clocks = []
         self.load_clocks()
         self.show_all()
 
-    def unselect_all(self):
-        self.iconview.unselect_all()
+    def set_selection_mode(self, active):
+        self.iconview.set_selection_mode(active)
 
-    def _on_selection_changed(self, iconview):
-        items = iconview.get_selected_items()
-        if items:
-            path = iconview.get_selected_items()[0]
-            d = self.liststore[path][2]
-            self.emit("show-clock", d)
+    def _on_item_activated(self, iconview, path):
+        d = self.liststore[path][3]
+        self.emit("show-clock", d)
 
-    def set_addButton(self, btn):
-        self.addButton = btn
+    def _on_selection_changed(self, iconview):
+        pass
 
     def load_clocks(self):
         self.clocks = worldclockstorage.load_clocks()
@@ -144,7 +137,8 @@ class World(Clock):
     def add_clock_widget(self, location):
         d = DigitalClock(location)
         name = d.location.get_city_name()
-        view_iter = self.liststore.append([d.drawing.pixbuf,
+        view_iter = self.liststore.append([False,
+                                           d.drawing.pixbuf,
                                            "<b>" + name + "</b>",
                                            d])
         d.set_iter(self.liststore, view_iter)
@@ -186,41 +180,40 @@ class World(Clock):
 class Alarm(Clock):
     def __init__(self):
         Clock.__init__(self, _("Alarm"), True, True)
-        self.liststore = liststore = Gtk.ListStore(Pixbuf, str,
-                                                  GObject.TYPE_PYOBJECT,
-                                                  GObject.TYPE_PYOBJECT)
-        self.iconview = iconview = Gtk.IconView.new()
+
+        self.liststore = Gtk.ListStore(bool,
+                                       Pixbuf,
+                                       str,
+                                       GObject.TYPE_PYOBJECT,
+                                       GObject.TYPE_PYOBJECT)
+        self.iconview = SelectableIconView(self.liststore, 0, 1, 2)
 
         self.empty_view = EmptyPlaceholder(
                 "alarm-symbolic",
                 _("Select <b>New</b> to add an alarm"))
 
-        iconview.set_model(liststore)
-
-        iconview.set_spacing(3)
-        iconview.set_pixbuf_column(0)
-        iconview.get_style_context().add_class('content-view')
+        self.iconview.set_spacing(3)
+        self.iconview.get_style_context().add_class('content-view')
 
-        renderer_text = Gtk.CellRendererText()
-        renderer_text.set_alignment(0.5, 0.5)
-        iconview.pack_start(renderer_text, True)
-        iconview.add_attribute(renderer_text, "markup", 1)
-
-        self.scrolledwindow = Gtk.ScrolledWindow()
-        self.scrolledwindow.add(iconview)
+        self.scrolledwindow = scrolledwindow = Gtk.ScrolledWindow()
+        scrolledwindow.add(self.iconview)
 
-        iconview.connect('selection-changed', self._on_selection_changed)
+        self.iconview.connect("item-activated", self._on_item_activated)
+        self.iconview.connect("selection-changed", self._on_selection_changed)
 
         self.alarms = []
         self.load_alarms()
         self.show_all()
 
+    def set_selection_mode(self, active):
+        self.iconview.set_selection_mode(active)
+
+    def _on_item_activated(self, iconview, path):
+        alarm = self.liststore[path][-1]
+        self.open_edit_dialog(alarm)
+
     def _on_selection_changed(self, iconview):
-        items = iconview.get_selected_items()
-        if items:
-            path = iconview.get_selected_items()[0]
-            alarm = self.liststore[path][-1]
-            self.open_edit_dialog(alarm)
+        pass
 
     def load_alarms(self):
         handler = ICSHandler()
@@ -262,7 +255,8 @@ class Alarm(Clock):
         timestr = alarm.get_time_as_string()
         repeat = alarm.get_alarm_repeat_string()
         widget = AlarmWidget(timestr, repeat)
-        view_iter = self.liststore.append([widget.drawing.pixbuf,
+        view_iter = self.liststore.append([False,
+                                           widget.drawing.pixbuf,
                                            "<b>" + name + "</b>",
                                            widget,
                                            alarm.get_vevent()])
diff --git a/gnomeclocks/widgets.py b/gnomeclocks/widgets.py
index 2325fe2..985bbdb 100644
--- a/gnomeclocks/widgets.py
+++ b/gnomeclocks/widgets.py
@@ -541,3 +541,131 @@ class EmptyPlaceholder(Gtk.Box):
         self.pack_start(text, False, False, 6)
         self.pack_start(Gtk.Label(), True, True, 0)
         self.show_all()
+
+
+# Python version of the gd-toggle-pixbuf-renderer of gnome-documents
+# we should use those widgets directly at some point, but for now
+# it is easier to just reimplement this renderer than include and build
+# a C library
+class TogglePixbufRenderer(Gtk.CellRendererPixbuf):
+
+    __gproperties__ = {
+         "active" : (GObject.TYPE_BOOLEAN,
+                    "Active",
+                    "Whether the cell renderer is active",
+                    False,
+                    GObject.PARAM_READWRITE),
+         "toggle-visible" : (GObject.TYPE_BOOLEAN,
+                             "Toggle visible",
+                             "Whether to draw the toggle indicator",
+                             False,
+                             GObject.PARAM_READWRITE)
+    }
+
+    def __init__(self):
+        Gtk.CellRendererPixbuf.__init__(self)
+        self._active = False
+        self._toggle_visible = False
+
+    def do_render(self, cr, widget, background_area, cell_area, flags):
+        Gtk.CellRendererPixbuf.do_render(self, cr, widget, background_area, cell_area, flags)
+
+        if not self._toggle_visible:
+            return
+
+        xpad, ypad = self.get_padding()
+        direction = widget.get_direction()
+
+        # FIXME: currently broken with g-i
+        # icon_size = widget.style_get_property("check-icon-size")
+        icon_size = 40
+
+        if direction == Gtk.TextDirection.RTL:
+            x_offset = xpad;
+        else:
+            x_offset = cell_area.width - icon_size - xpad
+
+        check_x = cell_area.x + x_offset
+        check_y = cell_area.y + cell_area.height - icon_size - ypad
+
+        context = widget.get_style_context()
+        context.save()
+        context.add_class(Gtk.STYLE_CLASS_CHECK)
+
+        if self._active:
+            context.set_state(Gtk.StateFlags.ACTIVE)
+
+        Gtk.render_check(context, cr, check_x, check_y, icon_size, icon_size)
+
+        context.restore()
+
+    def do_get_size(self, widget, cell_area):
+
+        # FIXME: currently broken with g-i
+        # icon_size = widget.style_get_property("check-icon-size")
+        icon_size = 40
+
+        x_offset, y_offset, width, height = Gtk.CellRendererPixbuf.do_get_size(self, widget, cell_area)
+
+        width += icon_size / 4
+
+        return (x_offset, y_offset, width, height)
+
+    def do_get_property(self, prop):
+        if prop.name == "active":
+            return self._active
+        elif prop.name == "toggle-visible":
+            return self._toggle_visible
+        else:
+            raise AttributeError, 'unknown property %s' % prop.name
+
+    def do_set_property(self, prop, value):
+        if prop.name == "active":
+            self._active = value
+        elif prop.name == "toggle-visible":
+            self._toggle_visible = value
+        else:
+            raise AttributeError, 'unknown property %s' % prop.name
+
+
+class SelectableIconView(Gtk.IconView):
+    def __init__(self, model, selection_col, pixbuf_col, text_col = None):
+        Gtk.IconView.__init__(self, model)
+
+        self.selection_mode = False
+
+        self.selection_col = selection_col
+
+        self.renderer_pixbuf = TogglePixbufRenderer();
+        self.renderer_pixbuf.set_alignment(0.5, 0.5)
+        self.pack_start(self.renderer_pixbuf, False)
+        self.add_attribute(self.renderer_pixbuf, "active", selection_col)
+        self.add_attribute(self.renderer_pixbuf, "pixbuf", pixbuf_col)
+
+        if text_col:
+            renderer_text = Gtk.CellRendererText()
+            renderer_text.set_alignment(0.5, 0.5)
+            self.pack_start(renderer_text, True)
+            self.add_attribute(renderer_text, "markup", text_col)
+
+    def set_selection_mode(self, active):
+        self.selection_mode = active
+        self.renderer_pixbuf.set_property("toggle_visible", active)
+
+    # FIXME: override both button press and release to check
+    # that a specfic item is clicked? see libgd...
+    def do_button_press_event (self, event):
+        path = self.get_path_at_pos(event.x, event.y);
+
+        if path:
+            if self.selection_mode:
+                i = self.get_model().get_iter(path)
+                if i:
+                    selected = self.get_model().get_value(i, self.selection_col)
+                    self.get_model().set_value(i, self.selection_col, not selected)
+                    self.emit("selection-changed")
+            else:
+                self.emit("item-activated", path)
+
+        return False
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]