Merge branch 'treeview_perf2-try2' of https://github.com/godiard/sugar-toolkit-gtk3 into godiard-treeview_perf2-try2
This commit is contained in:
commit
5818721818
@ -21,7 +21,7 @@ treeview.show()
|
|||||||
col = Gtk.TreeViewColumn()
|
col = Gtk.TreeViewColumn()
|
||||||
treeview.append_column(col)
|
treeview.append_column(col)
|
||||||
|
|
||||||
cell_icon = CellRendererIcon(treeview)
|
cell_icon = CellRendererIcon()
|
||||||
cell_icon.props.width = style.GRID_CELL_SIZE
|
cell_icon.props.width = style.GRID_CELL_SIZE
|
||||||
cell_icon.props.height = style.GRID_CELL_SIZE
|
cell_icon.props.height = style.GRID_CELL_SIZE
|
||||||
cell_icon.props.size = style.SMALL_ICON_SIZE
|
cell_icon.props.size = style.SMALL_ICON_SIZE
|
||||||
|
71
examples/scrollingdetector.py
Normal file
71
examples/scrollingdetector.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
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
|
||||||
|
from sugar3.graphics.palettewindow import TreeViewInvoker
|
||||||
|
import common
|
||||||
|
|
||||||
|
|
||||||
|
def _scroll_start_cb(event, treeview, invoker):
|
||||||
|
print "Scroll starts"
|
||||||
|
invoker.detach()
|
||||||
|
|
||||||
|
def _scroll_end_cb(event, treeview, invoker):
|
||||||
|
print "Scroll ends"
|
||||||
|
invoker.attach_treeview(treeview)
|
||||||
|
|
||||||
|
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()
|
||||||
|
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)
|
||||||
|
|
||||||
|
invoker = TreeViewInvoker()
|
||||||
|
invoker.attach_treeview(treeview)
|
||||||
|
|
||||||
|
detector = ScrollingDetector(scrolled)
|
||||||
|
detector.connect('scroll-start', _scroll_start_cb, treeview, invoker)
|
||||||
|
detector.connect('scroll-end', _scroll_end_cb, treeview, invoker)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
time_ini = time.time()
|
||||||
|
common.main(test)
|
@ -18,6 +18,7 @@ sugar_PYTHON = \
|
|||||||
panel.py \
|
panel.py \
|
||||||
radiopalette.py \
|
radiopalette.py \
|
||||||
radiotoolbutton.py \
|
radiotoolbutton.py \
|
||||||
|
scrollingdetector.py \
|
||||||
style.py \
|
style.py \
|
||||||
toggletoolbutton.py \
|
toggletoolbutton.py \
|
||||||
toolbarbox.py \
|
toolbarbox.py \
|
||||||
|
@ -825,9 +825,11 @@ class CellRendererIcon(Gtk.CellRenderer):
|
|||||||
'clicked': (GObject.SignalFlags.RUN_FIRST, None, [object]),
|
'clicked': (GObject.SignalFlags.RUN_FIRST, None, [object]),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, tree_view):
|
def __init__(self, treeview=None):
|
||||||
from sugar3.graphics.palette import CellRendererInvoker
|
# treeview is not used anymore, is here just to not break the API
|
||||||
|
if treeview is not None:
|
||||||
|
logging.warning('CellRendererIcon: treeview parameter in '
|
||||||
|
'constructor is deprecated')
|
||||||
self._buffer = _IconBuffer()
|
self._buffer = _IconBuffer()
|
||||||
self._buffer.cache = True
|
self._buffer.cache = True
|
||||||
self._xo_color = None
|
self._xo_color = None
|
||||||
@ -836,36 +838,28 @@ class CellRendererIcon(Gtk.CellRenderer):
|
|||||||
self._prelit_fill_color = None
|
self._prelit_fill_color = None
|
||||||
self._prelit_stroke_color = None
|
self._prelit_stroke_color = None
|
||||||
self._active_state = False
|
self._active_state = False
|
||||||
self._palette_invoker = CellRendererInvoker()
|
|
||||||
self._cached_offsets = None
|
self._cached_offsets = None
|
||||||
|
|
||||||
Gtk.CellRenderer.__init__(self)
|
Gtk.CellRenderer.__init__(self)
|
||||||
|
|
||||||
tree_view.connect('button-press-event',
|
self._is_scrolling = False
|
||||||
self.__button_press_event_cb)
|
|
||||||
tree_view.connect('button-release-event',
|
|
||||||
self.__button_release_event_cb)
|
|
||||||
|
|
||||||
self._palette_invoker.attach_cell_renderer(tree_view, self)
|
def connect_to_scroller(self, scrolled):
|
||||||
|
scrolled.connect('scroll-start', self._scroll_start_cb)
|
||||||
|
scrolled.connect('scroll-end', self._scroll_end_cb)
|
||||||
|
|
||||||
def __del__(self):
|
def _scroll_start_cb(self, event):
|
||||||
self._palette_invoker.detach()
|
self._is_scrolling = True
|
||||||
|
|
||||||
def __button_press_event_cb(self, widget, event):
|
def _scroll_end_cb(self, event):
|
||||||
if self._point_in_cell_renderer(widget, event.x, event.y):
|
self._is_scrolling = False
|
||||||
self._active_state = True
|
|
||||||
|
|
||||||
def __button_release_event_cb(self, widget, event):
|
def is_scrolling(self):
|
||||||
self._active_state = False
|
return self._is_scrolling
|
||||||
|
|
||||||
def create_palette(self):
|
def create_palette(self):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_palette_invoker(self):
|
|
||||||
return self._palette_invoker
|
|
||||||
|
|
||||||
palette_invoker = GObject.property(type=object, getter=get_palette_invoker)
|
|
||||||
|
|
||||||
def set_file_name(self, value):
|
def set_file_name(self, value):
|
||||||
if self._buffer.file_name != value:
|
if self._buffer.file_name != value:
|
||||||
self._buffer.file_name = value
|
self._buffer.file_name = value
|
||||||
@ -964,32 +958,9 @@ class CellRendererIcon(Gtk.CellRenderer):
|
|||||||
flags):
|
flags):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _point_in_cell_renderer(self, tree_view, x=None, y=None):
|
|
||||||
"""Check if the point with coordinates x, y is inside this icon.
|
|
||||||
|
|
||||||
If the x, y coordinates are not given, they are taken from the
|
|
||||||
pointer current position.
|
|
||||||
|
|
||||||
"""
|
|
||||||
if x is None and y is None:
|
|
||||||
x, y = tree_view.get_pointer()
|
|
||||||
x, y = tree_view.convert_widget_to_bin_window_coords(x, y)
|
|
||||||
pos = tree_view.get_path_at_pos(int(x), int(y))
|
|
||||||
if pos is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
path_, column, x, y_ = pos
|
|
||||||
|
|
||||||
for cell_renderer in column.get_cells():
|
|
||||||
if cell_renderer == self:
|
|
||||||
cell_x, cell_width = column.cell_get_position(cell_renderer)
|
|
||||||
if x > cell_x and x < (cell_x + cell_width):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def do_render(self, cr, widget, background_area, cell_area, flags):
|
def do_render(self, cr, widget, background_area, cell_area, flags):
|
||||||
|
if not self._is_scrolling:
|
||||||
|
|
||||||
context = widget.get_style_context()
|
context = widget.get_style_context()
|
||||||
context.save()
|
context.save()
|
||||||
context.add_class("sugar-icon-cell")
|
context.add_class("sugar-icon-cell")
|
||||||
@ -999,7 +970,8 @@ class CellRendererIcon(Gtk.CellRenderer):
|
|||||||
x, y = widget.get_pointer()
|
x, y = widget.get_pointer()
|
||||||
x, y = widget.convert_widget_to_bin_window_coords(x, y)
|
x, y = widget.convert_widget_to_bin_window_coords(x, y)
|
||||||
return ((cell_area.x <= x <= cell_area.x + cell_area.width)
|
return ((cell_area.x <= x <= cell_area.x + cell_area.width)
|
||||||
and (cell_area.y <= y <= cell_area.y + cell_area.height))
|
and
|
||||||
|
(cell_area.y <= y <= cell_area.y + cell_area.height))
|
||||||
|
|
||||||
pointer_inside = is_pointer_inside()
|
pointer_inside = is_pointer_inside()
|
||||||
|
|
||||||
@ -1039,6 +1011,13 @@ class CellRendererIcon(Gtk.CellRenderer):
|
|||||||
else:
|
else:
|
||||||
self._buffer.fill_color = fill_color
|
self._buffer.fill_color = fill_color
|
||||||
self._buffer.stroke_color = stroke_color
|
self._buffer.stroke_color = stroke_color
|
||||||
|
else:
|
||||||
|
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()
|
surface = self._buffer.get_surface()
|
||||||
if surface is None:
|
if surface is None:
|
||||||
|
@ -38,13 +38,14 @@ from sugar3.graphics.palettewindow import PaletteWindow, \
|
|||||||
from sugar3.graphics.palettemenu import PaletteMenuItem
|
from sugar3.graphics.palettemenu import PaletteMenuItem
|
||||||
|
|
||||||
from sugar3.graphics.palettewindow import MouseSpeedDetector, Invoker, \
|
from sugar3.graphics.palettewindow import MouseSpeedDetector, Invoker, \
|
||||||
WidgetInvoker, CursorInvoker, ToolInvoker, CellRendererInvoker
|
WidgetInvoker, CursorInvoker, ToolInvoker, TreeViewInvoker
|
||||||
|
|
||||||
assert MouseSpeedDetector
|
assert MouseSpeedDetector
|
||||||
assert Invoker
|
assert Invoker
|
||||||
assert WidgetInvoker
|
assert WidgetInvoker
|
||||||
assert CursorInvoker
|
assert CursorInvoker
|
||||||
assert ToolInvoker
|
assert ToolInvoker
|
||||||
assert CellRendererInvoker
|
assert TreeViewInvoker
|
||||||
|
|
||||||
|
|
||||||
class _HeaderItem(Gtk.MenuItem):
|
class _HeaderItem(Gtk.MenuItem):
|
||||||
@ -418,6 +419,7 @@ class Palette(PaletteWindow):
|
|||||||
if self._palette_state == self.PRIMARY:
|
if self._palette_state == self.PRIMARY:
|
||||||
self._secondary_box.show()
|
self._secondary_box.show()
|
||||||
|
|
||||||
|
if self._widget is not None:
|
||||||
self._full_request = self._widget.size_request()
|
self._full_request = self._widget.size_request()
|
||||||
|
|
||||||
if self._palette_state == self.PRIMARY:
|
if self._palette_state == self.PRIMARY:
|
||||||
|
@ -35,6 +35,7 @@ from gi.repository import SugarGestures
|
|||||||
from sugar3.graphics import palettegroup
|
from sugar3.graphics import palettegroup
|
||||||
from sugar3.graphics import animator
|
from sugar3.graphics import animator
|
||||||
from sugar3.graphics import style
|
from sugar3.graphics import style
|
||||||
|
from sugar3.graphics.icon import CellRendererIcon
|
||||||
|
|
||||||
|
|
||||||
def _calculate_gap(a, b):
|
def _calculate_gap(a, b):
|
||||||
@ -223,9 +224,6 @@ class _PaletteMenuWidget(Gtk.Menu):
|
|||||||
x = event.x_root
|
x = event.x_root
|
||||||
y = event.y_root
|
y = event.y_root
|
||||||
|
|
||||||
if type(self._invoker) is CellRendererInvoker:
|
|
||||||
in_invoker = self._invoker.point_in_cell_renderer(x, y)
|
|
||||||
else:
|
|
||||||
rect = self._invoker.get_rect()
|
rect = self._invoker.get_rect()
|
||||||
in_invoker = x >= rect.x and x < (rect.x + rect.width) \
|
in_invoker = x >= rect.x and x < (rect.x + rect.width) \
|
||||||
and y >= rect.y and y < (rect.y + rect.height)
|
and y >= rect.y and y < (rect.y + rect.height)
|
||||||
@ -238,9 +236,6 @@ class _PaletteMenuWidget(Gtk.Menu):
|
|||||||
x = event.x_root
|
x = event.x_root
|
||||||
y = event.y_root
|
y = event.y_root
|
||||||
|
|
||||||
if type(self._invoker) is CellRendererInvoker:
|
|
||||||
in_invoker = self._invoker.point_in_cell_renderer(x, y)
|
|
||||||
else:
|
|
||||||
rect = self._invoker.get_rect()
|
rect = self._invoker.get_rect()
|
||||||
in_invoker = x >= rect.x and x < (rect.x + rect.width) \
|
in_invoker = x >= rect.x and x < (rect.x + rect.width) \
|
||||||
and y >= rect.y and y < (rect.y + rect.height)
|
and y >= rect.y and y < (rect.y + rect.height)
|
||||||
@ -399,6 +394,7 @@ class _PaletteWindowWidget(Gtk.Window):
|
|||||||
|
|
||||||
def popup(self, invoker):
|
def popup(self, invoker):
|
||||||
if self.get_visible():
|
if self.get_visible():
|
||||||
|
logging.error('PaletteWindowWidget popup get_visible True')
|
||||||
return
|
return
|
||||||
self.connect('enter-notify-event', self.__enter_notify_event_cb)
|
self.connect('enter-notify-event', self.__enter_notify_event_cb)
|
||||||
self.connect('leave-notify-event', self.__leave_notify_event_cb)
|
self.connect('leave-notify-event', self.__leave_notify_event_cb)
|
||||||
@ -618,6 +614,9 @@ class PaletteWindow(GObject.GObject):
|
|||||||
logging.error('Cannot update the palette position.')
|
logging.error('Cannot update the palette position.')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self._widget is None:
|
||||||
|
return
|
||||||
|
|
||||||
req = self._widget.size_request()
|
req = self._widget.size_request()
|
||||||
# on Gtk 3.10, menu at the bottom of the screen are resized
|
# on Gtk 3.10, menu at the bottom of the screen are resized
|
||||||
# to not fall out, and report a wrong size.
|
# to not fall out, and report a wrong size.
|
||||||
@ -642,6 +641,8 @@ class PaletteWindow(GObject.GObject):
|
|||||||
return self._widget.size_request()
|
return self._widget.size_request()
|
||||||
|
|
||||||
def popup(self, immediate=False):
|
def popup(self, immediate=False):
|
||||||
|
if self._widget is None:
|
||||||
|
return
|
||||||
if self._invoker is not None:
|
if self._invoker is not None:
|
||||||
full_size_request = self.get_full_size_request()
|
full_size_request = self.get_full_size_request()
|
||||||
self._alignment = self._invoker.get_alignment(full_size_request)
|
self._alignment = self._invoker.get_alignment(full_size_request)
|
||||||
@ -1372,28 +1373,34 @@ class ToolInvoker(WidgetInvoker):
|
|||||||
self._widget.emit('clicked')
|
self._widget.emit('clicked')
|
||||||
|
|
||||||
|
|
||||||
class CellRendererInvoker(Invoker):
|
class TreeViewInvoker(Invoker):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Invoker.__init__(self)
|
Invoker.__init__(self)
|
||||||
|
|
||||||
self._position_hint = self.AT_CURSOR
|
|
||||||
self._tree_view = None
|
self._tree_view = None
|
||||||
self._cell_renderer = None
|
|
||||||
self._motion_hid = None
|
self._motion_hid = None
|
||||||
self._leave_hid = None
|
self._leave_hid = None
|
||||||
self._release_hid = None
|
self._release_hid = None
|
||||||
self._long_pressed_hid = None
|
self._long_pressed_hid = None
|
||||||
self.path = None
|
self._position_hint = self.AT_CURSOR
|
||||||
|
|
||||||
self._long_pressed_controller = SugarGestures.LongPressController()
|
self._long_pressed_controller = SugarGestures.LongPressController()
|
||||||
|
|
||||||
def attach_cell_renderer(self, tree_view, cell_renderer):
|
self._mouse_detector = MouseSpeedDetector(200, 5)
|
||||||
|
|
||||||
|
self._tree_view = None
|
||||||
|
self._path = None
|
||||||
|
self._column = None
|
||||||
|
|
||||||
|
self.palette = None
|
||||||
|
|
||||||
|
def attach_treeview(self, tree_view):
|
||||||
self._tree_view = tree_view
|
self._tree_view = tree_view
|
||||||
self._cell_renderer = cell_renderer
|
|
||||||
|
|
||||||
self._motion_hid = tree_view.connect('motion-notify-event',
|
self._motion_hid = tree_view.connect('motion-notify-event',
|
||||||
self.__motion_notify_event_cb)
|
self.__motion_notify_event_cb)
|
||||||
|
self._enter_hid = tree_view.connect('enter-notify-event',
|
||||||
|
self.__enter_notify_event_cb)
|
||||||
self._leave_hid = tree_view.connect('leave-notify-event',
|
self._leave_hid = tree_view.connect('leave-notify-event',
|
||||||
self.__leave_notify_event_cb)
|
self.__leave_notify_event_cb)
|
||||||
self._release_hid = tree_view.connect('button-release-event',
|
self._release_hid = tree_view.connect('button-release-event',
|
||||||
@ -1403,129 +1410,104 @@ class CellRendererInvoker(Invoker):
|
|||||||
self._long_pressed_controller.attach(
|
self._long_pressed_controller.attach(
|
||||||
tree_view,
|
tree_view,
|
||||||
SugarGestures.EventControllerFlags.NONE)
|
SugarGestures.EventControllerFlags.NONE)
|
||||||
Invoker.attach(self, cell_renderer)
|
|
||||||
|
self._mouse_detector.connect('motion-slow', self.__mouse_slow_cb)
|
||||||
|
self._mouse_detector.parent = tree_view
|
||||||
|
Invoker.attach(self, tree_view)
|
||||||
|
|
||||||
def detach(self):
|
def detach(self):
|
||||||
Invoker.detach(self)
|
Invoker.detach(self)
|
||||||
self._tree_view.disconnect(self._motion_hid)
|
self._tree_view.disconnect(self._motion_hid)
|
||||||
|
self._tree_view.disconnect(self._enter_hid)
|
||||||
self._tree_view.disconnect(self._leave_hid)
|
self._tree_view.disconnect(self._leave_hid)
|
||||||
self._tree_view.disconnect(self._release_hid)
|
self._tree_view.disconnect(self._release_hid)
|
||||||
self._long_pressed_controller.detach(self._tree_view)
|
self._long_pressed_controller.detach(self._tree_view)
|
||||||
self._long_pressed_controller.disconnect(self._long_pressed_hid)
|
self._long_pressed_controller.disconnect(self._long_pressed_hid)
|
||||||
|
self._mouse_detector.disconnect_by_func(self.__mouse_slow_cb)
|
||||||
|
|
||||||
def get_rect(self):
|
def get_rect(self):
|
||||||
allocation = self._tree_view.get_allocation()
|
return self._tree_view.get_background_area(self._path, self._column)
|
||||||
window = self._tree_view.get_window()
|
|
||||||
if window is not None:
|
|
||||||
res, x, y = window.get_origin()
|
|
||||||
else:
|
|
||||||
logging.warning(
|
|
||||||
"Trying to position palette with invoker that's not realized.")
|
|
||||||
x = 0
|
|
||||||
y = 0
|
|
||||||
|
|
||||||
rect = Gdk.Rectangle()
|
def get_toplevel(self):
|
||||||
rect.x = x + allocation.x
|
return self._tree_view.get_toplevel()
|
||||||
rect.y = y + allocation.y
|
|
||||||
|
|
||||||
rect.width = allocation.width
|
|
||||||
rect.height = allocation.height
|
|
||||||
|
|
||||||
return rect
|
|
||||||
|
|
||||||
def __motion_notify_event_cb(self, widget, event):
|
def __motion_notify_event_cb(self, widget, event):
|
||||||
if event.window != widget.get_bin_window():
|
try:
|
||||||
return
|
path, column, x_, y_ = self._tree_view.get_path_at_pos(
|
||||||
if self.point_in_cell_renderer(event.x, event.y):
|
int(event.x), int(event.y))
|
||||||
|
if path != self._path or column != self._column:
|
||||||
|
self._redraw_cell(self._path, self._column)
|
||||||
|
self._redraw_cell(path, column)
|
||||||
|
|
||||||
|
self._path = path
|
||||||
|
self._column = column
|
||||||
|
|
||||||
tree_view = self._tree_view
|
|
||||||
path, column_, x_, y_ = tree_view.get_path_at_pos(int(event.x),
|
|
||||||
int(event.y))
|
|
||||||
if path != self.path:
|
|
||||||
if self.path is not None:
|
|
||||||
self._redraw_path(self.path)
|
|
||||||
if path is not None:
|
|
||||||
self._redraw_path(path)
|
|
||||||
if self.palette is not None:
|
if self.palette is not None:
|
||||||
self.palette.popdown(immediate=True)
|
self.palette.popdown(immediate=True)
|
||||||
self.palette = None
|
self.palette = None
|
||||||
self.path = path
|
|
||||||
|
|
||||||
if event.get_source_device().get_source() == \
|
self._mouse_detector.start()
|
||||||
Gdk.InputSource.TOUCHSCREEN:
|
except TypeError:
|
||||||
return False
|
# tree_view.get_path_at_pos() fail if x,y poition is over
|
||||||
self.notify_mouse_enter()
|
# a empty area
|
||||||
else:
|
pass
|
||||||
if self.path is not None:
|
|
||||||
self._redraw_path(self.path)
|
|
||||||
self.path = None
|
|
||||||
|
|
||||||
if event.get_source_device().get_source() == \
|
def _redraw_cell(self, path, column):
|
||||||
Gdk.InputSource.TOUCHSCREEN:
|
|
||||||
return False
|
|
||||||
self.notify_mouse_leave()
|
|
||||||
|
|
||||||
def _redraw_path(self, path):
|
|
||||||
column = None
|
|
||||||
for column in self._tree_view.get_columns():
|
|
||||||
if self._cell_renderer in column.get_cells():
|
|
||||||
break
|
|
||||||
assert column is not None
|
|
||||||
area = self._tree_view.get_background_area(path, column)
|
area = self._tree_view.get_background_area(path, column)
|
||||||
x, y = \
|
x, y = \
|
||||||
self._tree_view.convert_bin_window_to_widget_coords(area.x, area.y)
|
self._tree_view.convert_bin_window_to_widget_coords(area.x, area.y)
|
||||||
self._tree_view.queue_draw_area(x, y, area.width, area.height)
|
self._tree_view.queue_draw_area(x, y, area.width, area.height)
|
||||||
|
|
||||||
|
def __enter_notify_event_cb(self, widget, event):
|
||||||
|
self._mouse_detector.start()
|
||||||
|
|
||||||
def __leave_notify_event_cb(self, widget, event):
|
def __leave_notify_event_cb(self, widget, event):
|
||||||
if event.mode == Gdk.CrossingMode.NORMAL:
|
self._mouse_detector.stop()
|
||||||
self.notify_mouse_leave()
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __button_release_event_cb(self, widget, event):
|
def __button_release_event_cb(self, widget, event):
|
||||||
if event.button == 1 and self.point_in_cell_renderer(event.x,
|
x, y = int(event.x), int(event.y)
|
||||||
event.y):
|
path, column, cell_x, cell_y = self._tree_view.get_path_at_pos(x, y)
|
||||||
tree_view = self._tree_view
|
self._path = path
|
||||||
path, column_, x_, y_ = tree_view.get_path_at_pos(int(event.x),
|
self._column = column
|
||||||
int(event.y))
|
if event.button == 1:
|
||||||
self._cell_renderer.emit('clicked', path)
|
# left mouse button
|
||||||
|
if self.palette is not None:
|
||||||
|
self.palette.popdown(immediate=True)
|
||||||
|
# NOTE: we don't use columns with more than one cell
|
||||||
|
cellrenderer = column.get_cells()[0]
|
||||||
|
if cellrenderer is not None and \
|
||||||
|
isinstance(cellrenderer, CellRendererIcon):
|
||||||
|
cellrenderer.emit('clicked', path)
|
||||||
# So the treeview receives it and knows a drag isn't going on
|
# So the treeview receives it and knows a drag isn't going on
|
||||||
return False
|
return False
|
||||||
if event.button == 3 and self.point_in_cell_renderer(event.x,
|
if event.button == 3:
|
||||||
event.y):
|
# right mouse button
|
||||||
|
self._mouse_detector.stop()
|
||||||
|
self._change_palette()
|
||||||
self.notify_right_click()
|
self.notify_right_click()
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __long_pressed_event_cb(self, controller, x, y, widget):
|
def __long_pressed_event_cb(self, controller, x, y, widget):
|
||||||
if self.point_in_cell_renderer(x, y):
|
path, column, x_, y_ = self._tree_view.get_path_at_pos(x, y)
|
||||||
|
self._path = path
|
||||||
|
self._column = column
|
||||||
|
self._change_palette()
|
||||||
self.notify_right_click()
|
self.notify_right_click()
|
||||||
|
|
||||||
def point_in_cell_renderer(self, event_x, event_y):
|
def __mouse_slow_cb(self, widget):
|
||||||
pos = self._tree_view.get_path_at_pos(int(event_x), int(event_y))
|
self._mouse_detector.stop()
|
||||||
if pos is None:
|
self._change_palette()
|
||||||
return False
|
self.emit('mouse-enter')
|
||||||
|
|
||||||
path_, column, x, y_ = pos
|
def _change_palette(self):
|
||||||
|
if hasattr(self._tree_view, 'create_palette'):
|
||||||
for cell_renderer in column.get_cells():
|
self.palette = self._tree_view.create_palette(
|
||||||
if cell_renderer == self._cell_renderer:
|
self._path, self._column)
|
||||||
cell_x, cell_width = column.cell_get_position(cell_renderer)
|
else:
|
||||||
if x > cell_x and x < (cell_x + cell_width):
|
self.palette = None
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_toplevel(self):
|
|
||||||
return self._tree_view.get_toplevel()
|
|
||||||
|
|
||||||
def notify_popup(self):
|
|
||||||
Invoker.notify_popup(self)
|
|
||||||
|
|
||||||
def notify_popdown(self):
|
def notify_popdown(self):
|
||||||
Invoker.notify_popdown(self)
|
Invoker.notify_popdown(self)
|
||||||
self.palette = None
|
self.palette = None
|
||||||
|
|
||||||
def get_default_position(self):
|
|
||||||
return self.AT_CURSOR
|
|
||||||
|
61
src/sugar3/graphics/scrollingdetector.py
Normal file
61
src/sugar3/graphics/scrollingdetector.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
class ScrollingDetector(GObject.GObject):
|
||||||
|
"""
|
||||||
|
ScollingDetector emit signals when a ScrolledWindow starts and
|
||||||
|
finish scrolling. Other widets can use that information to
|
||||||
|
avoid do performance expensive operations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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)
|
Loading…
Reference in New Issue
Block a user