diff --git a/examples/scrollingdetector.py b/examples/scrollingdetector.py new file mode 100644 index 00000000..f6845223 --- /dev/null +++ b/examples/scrollingdetector.py @@ -0,0 +1,58 @@ +import os +import time + +from gi.repository import Gtk + +from sugar3.graphics import style +from sugar3.graphics.icon import CellRendererIcon +from sugar3.graphics.xocolor import XoColor +from sugar3.graphics.scrollingdetector import ScrollingDetector +import common + + +test = common.Test() +test.show() + +model = Gtk.ListStore(str) + +data_dir = os.getenv('GTK_DATA_PREFIX', '/usr/') + +iconlist = os.listdir(os.path.join(data_dir, + 'share/icons/sugar/scalable/actions/')) +print "Displaying %s icons" % len(iconlist) +for icon in iconlist: + icon = os.path.basename(icon) + icon = icon[:icon.find('.')] + model.append([icon]) + +scrolled = Gtk.ScrolledWindow() +scrolled.set_size_request(800, 800) +treeview = Gtk.TreeView() + +treeview.set_model(model) +scrolled.add(treeview) +test.pack_start(scrolled, True, True, 0) +test.show_all() + +col = Gtk.TreeViewColumn() +treeview.append_column(col) + +xo_color = XoColor('#FF0000,#00FF00') +cell_icon = CellRendererIcon(treeview) +cell_icon.props.width = style.GRID_CELL_SIZE +cell_icon.props.height = style.GRID_CELL_SIZE +cell_icon.props.size = style.STANDARD_ICON_SIZE +cell_icon.props.xo_color = xo_color + +col.pack_start(cell_icon, expand=False) +col.add_attribute(cell_icon, 'icon-name', 0) +cell_text = Gtk.CellRendererText() +col.pack_start(cell_text, expand=True) +col.add_attribute(cell_text, 'text', 0) + +detector = ScrollingDetector(scrolled) +detector.connect_treeview(treeview) + +if __name__ == '__main__': + time_ini = time.time() + common.main(test) diff --git a/src/sugar3/graphics/Makefile.am b/src/sugar3/graphics/Makefile.am index 344cc82d..0621750e 100644 --- a/src/sugar3/graphics/Makefile.am +++ b/src/sugar3/graphics/Makefile.am @@ -18,6 +18,7 @@ sugar_PYTHON = \ panel.py \ radiopalette.py \ radiotoolbutton.py \ + scrollingdetector.py \ style.py \ toggletoolbutton.py \ toolbarbox.py \ diff --git a/src/sugar3/graphics/icon.py b/src/sugar3/graphics/icon.py index fc798ee7..329b4b15 100644 --- a/src/sugar3/graphics/icon.py +++ b/src/sugar3/graphics/icon.py @@ -848,6 +848,24 @@ class CellRendererIcon(Gtk.CellRenderer): self._palette_invoker.attach_cell_renderer(tree_view, self) + self._tree_view = tree_view + self._is_scrolling = False + + def connect_to_scroller(self, scrolled): + scrolled.connect('scroll-start', self._scroll_start_cb) + scrolled.connect('scroll-end', self._scroll_end_cb) + + def _scroll_start_cb(self, event): + self._palette_invoker.detach() + self._is_scrolling = True + + def _scroll_end_cb(self, event): + self._palette_invoker.attach_cell_renderer(self._tree_view, self) + self._is_scrolling = False + + def is_scrolling(self): + return self._is_scrolling + def __del__(self): self._palette_invoker.detach() @@ -990,55 +1008,65 @@ class CellRendererIcon(Gtk.CellRenderer): return False def do_render(self, cr, widget, background_area, cell_area, flags): - context = widget.get_style_context() - context.save() - context.add_class("sugar-icon-cell") - - def is_pointer_inside(): - # widget is the treeview - x, y = widget.get_pointer() - x, y = widget.convert_widget_to_bin_window_coords(x, y) - return ((cell_area.x <= x <= cell_area.x + cell_area.width) - and (cell_area.y <= y <= cell_area.y + cell_area.height)) - - pointer_inside = is_pointer_inside() - - # The context will have prelight state if the mouse pointer is - # in the entire row, but we want that state if the pointer is - # in this cell only: - if flags & Gtk.CellRendererState.PRELIT: - if pointer_inside: - if self._active_state: - context.set_state(Gtk.StateFlags.ACTIVE) - else: - context.set_state(Gtk.StateFlags.NORMAL) + if not self._is_scrolling: + + context = widget.get_style_context() + context.save() + context.add_class("sugar-icon-cell") + + def is_pointer_inside(): + # widget is the treeview + x, y = widget.get_pointer() + x, y = widget.convert_widget_to_bin_window_coords(x, y) + return ((cell_area.x <= x <= cell_area.x + cell_area.width) + and + (cell_area.y <= y <= cell_area.y + cell_area.height)) + + pointer_inside = is_pointer_inside() + + # The context will have prelight state if the mouse pointer is + # in the entire row, but we want that state if the pointer is + # in this cell only: + if flags & Gtk.CellRendererState.PRELIT: + if pointer_inside: + if self._active_state: + context.set_state(Gtk.StateFlags.ACTIVE) + else: + context.set_state(Gtk.StateFlags.NORMAL) - Gtk.render_background( - context, cr, background_area.x, background_area.y, - background_area.width, background_area.height) + Gtk.render_background( + context, cr, background_area.x, background_area.y, + background_area.width, background_area.height) - if self._xo_color is not None: - stroke_color = self._xo_color.get_stroke_color() - fill_color = self._xo_color.get_fill_color() - prelit_fill_color = None - prelit_stroke_color = None - else: - stroke_color = self._stroke_color - fill_color = self._fill_color - prelit_fill_color = self._prelit_fill_color - prelit_stroke_color = self._prelit_stroke_color + if self._xo_color is not None: + stroke_color = self._xo_color.get_stroke_color() + fill_color = self._xo_color.get_fill_color() + prelit_fill_color = None + prelit_stroke_color = None + else: + stroke_color = self._stroke_color + fill_color = self._fill_color + prelit_fill_color = self._prelit_fill_color + prelit_stroke_color = self._prelit_stroke_color - has_prelit_colors = None not in [prelit_fill_color, - prelit_stroke_color] + has_prelit_colors = None not in [prelit_fill_color, + prelit_stroke_color] - if flags & Gtk.CellRendererState.PRELIT and has_prelit_colors and \ - pointer_inside: + if flags & Gtk.CellRendererState.PRELIT and has_prelit_colors and \ + pointer_inside: - self._buffer.fill_color = prelit_fill_color - self._buffer.stroke_color = prelit_stroke_color + self._buffer.fill_color = prelit_fill_color + self._buffer.stroke_color = prelit_stroke_color + else: + self._buffer.fill_color = fill_color + self._buffer.stroke_color = stroke_color else: - self._buffer.fill_color = fill_color - self._buffer.stroke_color = stroke_color + if self._xo_color is not None: + self._buffer.fill_color = self._xo_color.get_fill_color() + self._buffer.stroke_color = self._xo_color.get_stroke_color() + else: + self._buffer.fill_color = self._fill_color + self._buffer.stroke_color = self._stroke_color surface = self._buffer.get_surface() if surface is None: diff --git a/src/sugar3/graphics/scrollingdetector.py b/src/sugar3/graphics/scrollingdetector.py new file mode 100644 index 00000000..b44d35f8 --- /dev/null +++ b/src/sugar3/graphics/scrollingdetector.py @@ -0,0 +1,72 @@ +# Copyright (C) 2014, Sugarlabs +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +from gi.repository import GObject +from gi.repository import GLib + +from sugar3.graphics.icon import CellRendererIcon + + +class ScrollingDetector(GObject.GObject): + """ + """ + + scroll_start_signal = GObject.Signal('scroll-start') + scroll_end_signal = GObject.Signal('scroll-end') + + def __init__(self, scrolled_window, timeout=100): + self._scrolled_window = scrolled_window + self._timeout = timeout + self.is_scrolling = False + self._prev_value = 0 + + self.connect_scrolled_window() + GObject.GObject.__init__(self) + + def connect_scrolled_window(self): + adj = self._scrolled_window.get_vadjustment() + adj.connect('value-changed', self._value_changed_cb) + + def _check_scroll_cb(self, adj): + if (adj.props.value == self._prev_value): + self.is_scrolling = False + self.scroll_end_signal.emit() + return False + + self._prev_value = adj.props.value + return True + + def _value_changed_cb(self, adj): + if (self.is_scrolling): + return + + self.is_scrolling = True + self.scroll_start_signal.emit() + self._prev_value = adj.props.value + GLib.timeout_add(self._timeout, self._check_scroll_cb, adj) + + def connect_treeview(self, treeview): + """ + treeview -- Gtk.TreeView: a TreeView with CellRendererIcons already + added. + This method need be executed after all the columns and renderers + were added to the treeview. + """ + for column in treeview.get_columns(): + for cell_renderer in column.get_cells(): + if isinstance(cell_renderer, CellRendererIcon): + cell_renderer.connect_to_scroller(self)