Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@member.fsf.org>2009-08-20 13:02:56 (GMT)
committer Aleksey Lim <alsroot@member.fsf.org>2009-08-25 15:47:56 (GMT)
commitd108520f37360c5edc0ac20a1511cae352aa786c (patch)
treead00148404076ab50ec4763b4cd09e179e5b02d9 /src
parentf74e5d1fdcd96dba7f4e37dfc5e9b8ef8e6e02d3 (diff)
Implement smooth scrolling in TableView
Diffstat (limited to 'src')
-rw-r--r--src/jarabe/journal/browse/tableview.py356
-rw-r--r--src/jarabe/journal/thumbsview.py9
2 files changed, 263 insertions, 102 deletions
diff --git a/src/jarabe/journal/browse/tableview.py b/src/jarabe/journal/browse/tableview.py
index 34fe42b..43a871b 100644
--- a/src/jarabe/journal/browse/tableview.py
+++ b/src/jarabe/journal/browse/tableview.py
@@ -36,26 +36,30 @@ class TableCell:
def on_release(self, widget, event):
pass
-class TableView(gtk.Viewport):
- def __init__(self, cell_class, rows, cols):
- gobject.GObject.__init__(self)
-
- self._cell_class = cell_class
+class _SmoothTable(gtk.Bin):
+ __gsignals__ = {
+ 'set_scroll_adjustments': (gobject.SIGNAL_RUN_LAST, None,
+ (gtk.Adjustment, gtk.Adjustment)),
+ }
+
+ def __init__(self, cells, cell_class, rows, cols):
+ self._smooth_adjustment = None
+ self._smooth_window = None
self._rows = rows
- self._cols = cols
- self._cells = []
- self._model = None
- self._hover_selection = True
- self._full_adjustment = None
- self._full_height = 0
- self._selected_cell = None
+ self._heigth = 0
+ self.selected_cell = None
+ self.hover_selection = False
- self._table = gtk.Table()
- self._table.show()
+ gtk.Bin.__init__(self)
- for y in range(self._rows + 1):
- self._cells.append(self._cols * [None])
- for x in range(self._cols):
+ table = gtk.Table()
+ table.show()
+ self.add(table)
+
+ for y in range(rows + 1):
+ cells.append(cols * [None])
+
+ for x in range(cols):
canvas = hippo.Canvas()
canvas.show()
canvas.modify_bg(gtk.STATE_NORMAL,
@@ -66,40 +70,161 @@ class TableView(gtk.Viewport):
canvas.set_root(sel_box)
canvas.root = sel_box
- cell = self._cell_class()
+ cell = cell_class()
sel_box.append(cell, hippo.PACK_EXPAND)
- if self._hover_selection:
- canvas.connect('enter-notify-event',
- self.__enter_notify_event_cb, cell)
- canvas.connect('leave-notify-event',
- self.__leave_notify_event_cb)
+ canvas.connect('enter-notify-event',
+ self.__enter_notify_event_cb, cell)
+ canvas.connect('leave-notify-event',
+ self.__leave_notify_event_cb)
canvas.connect('button-release-event',
self.__button_release_event_cb, cell)
- self._table.attach(canvas, x, x + 1, y, y + 1,
+ table.attach(canvas, x, x + 1, y, y + 1,
gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
- self._cells[y][x] = (canvas, cell)
+ cells[y][x] = (canvas, cell)
+
+ def __button_release_event_cb(self, widget, event, cell):
+ cell.on_release(widget, event)
+
+ def __enter_notify_event_cb(self, canvas, event, cell):
+ if not self.hover_selection:
+ return
+ if cell.get_visible():
+ canvas.root.props.background_color = COLOR_SELECTED.get_int()
+ self.selected_cell = cell
+
+ def __leave_notify_event_cb(self, canvas, event):
+ if not self.hover_selection:
+ return
+ canvas.root.props.background_color = COLOR_BACKGROUND.get_int()
+ self.selected_cell = None
+
+ def do_size_allocate(self, allocation):
+ self.allocation = allocation
+ self._heigth = int(math.ceil(float(allocation.height) / self._rows))
+
+ if self.flags() & gtk.REALIZED:
+ self.window.move_resize(*allocation)
+ self._smooth_window.resize(allocation.width,
+ allocation.height + self._heigth)
+
+ self._set_adjustment_upper()
+ self._smooth_adjustment.changed()
+
+ table_allocation = allocation.copy()
+ table_allocation.height += self._heigth
+ self.child.size_allocate(table_allocation)
+
+ def do_size_request(self, requisition):
+ requisition.width, requisition.height = self.child.size_request()
+
+ def do_realize(self):
+ gtk.Bin.do_realize(self)
+
+ self.window = gtk.gdk.Window(self.get_parent_window(),
+ window_type=gtk.gdk.WINDOW_CHILD,
+ x=self.allocation.x,
+ y=self.allocation.y,
+ width=self.allocation.width,
+ height=self.allocation.height,
+ wclass=gtk.gdk.INPUT_OUTPUT,
+ colormap=self.get_colormap(),
+ event_mask=gtk.gdk.VISIBILITY_NOTIFY_MASK)
+
+ self.window.set_user_data(self)
+ self.set_style(self.style.attach(self.window))
+ self.style.set_background(self.window, gtk.STATE_NORMAL)
+
+ self._smooth_window = gtk.gdk.Window(self.window,
+ window_type=gtk.gdk.WINDOW_CHILD,
+ x=0,
+ y=int(-self._smooth_adjustment.value),
+ width=self.allocation.width,
+ height=self.allocation.height + self._heigth,
+ colormap=self.get_colormap(),
+ wclass=gtk.gdk.INPUT_OUTPUT,
+ event_mask=(self.get_events() | gtk.gdk.EXPOSURE_MASK | \
+ gtk.gdk.SCROLL_MASK))
+
+ self._smooth_window.set_user_data(self)
+ self.style.set_background(self._smooth_window, gtk.STATE_NORMAL)
+ self.child.set_parent_window(self._smooth_window)
+
+ self.queue_resize()
+
+ def do_unrealize(self):
+ self._smooth_window.set_user_data(None)
+ self._smooth_window.destroy()
+ self._smooth_window = None
+ gtk.Bin.do_unrealize(self)
+
+ def do_map(self):
+ gtk.Bin.do_map(self)
+ self._smooth_window.show()
+ self.window.show()
+
+ def do_set_scroll_adjustments(self, hadjustment, vadjustment):
+ if vadjustment is None or vadjustment == self._smooth_adjustment:
+ return
+
+ if self._smooth_adjustment is not None:
+ self._smooth_adjustment.disconnect_by_func(self.__value_changed_cb)
+
+ self._smooth_adjustment = vadjustment
+ self._set_adjustment_upper()
+ vadjustment.connect('value-changed', self.__value_changed_cb)
+ self.__value_changed_cb()
+
+ def __value_changed_cb(self, sender=None):
+ if not self.flags() & gtk.REALIZED:
+ return
+ self._smooth_window.move(0, int(-self._smooth_adjustment.value))
+ self.window.process_updates(True)
+
+ def _set_adjustment_upper(self):
+ adj = self._smooth_adjustment
+ adj.page_size = 0
+ adj.page_increment = 0
+ adj.lower = 0
+
+ if self._heigth != adj.upper:
+ adj.upper = self._heigth
+ adj.changed()
+
+ if adj.value > adj.upper:
+ adj.value = adj.upper
+ adj.value_changed()
+
+class TableView(gtk.Bin):
+ __gsignals__ = {
+ 'set_scroll_adjustments': (gobject.SIGNAL_RUN_LAST, None,
+ (gtk.Adjustment, gtk.Adjustment)),
+ }
+
+ def __init__(self, cell_class, rows, cols):
+ self._rows = rows
+ self._cols = cols
+ self._cells = []
+ self._model = None
+ self._full_adjustment = None
+ self._cell_height = 0
+ self._top_cell = None
+ self._last_adjustment = -1
+
+ gtk.Bin.__init__(self)
+
+ self._table = _SmoothTable(self._cells, cell_class, rows, cols)
+ self._table.show()
smooth_box = gtk.ScrolledWindow()
smooth_box.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
smooth_box.show()
- smooth_box.add_with_viewport(self._table)
+ smooth_box.add(self._table)
self.add(smooth_box)
self.connect('key-press-event', self.__key_press_event_cb)
- def do_set_scroll_adjustments(self, hadj, vadj):
- if vadj is None:
- return
- if self._full_adjustment is not None:
- self._full_adjustment.disconnect_by_func(
- self.__adjustment_value_changed)
- self._full_adjustment = vadj
- self._full_adjustment.connect('value-changed',
- self.__adjustment_value_changed)
- self._setup_adjustment()
-
def get_size(self):
return (self._cols, self._rows)
@@ -108,9 +233,10 @@ class TableView(gtk.Viewport):
return (frame[0],)
def set_cursor(self, cursor):
- if self._full_adjustment is None:
+ if self._full_adjustment is None or self._cell_height == 0:
return
- #self._full_adjustment.props.value = cursor
+ self._full_adjustment.props.value = self._cell_height * cursor
+ self._full_adjustment.changed()
def get_model(self):
return self._model
@@ -132,10 +258,10 @@ class TableView(gtk.Viewport):
getter=get_model, setter=set_model)
def get_hover_selection(self):
- return self._hover_selection
+ return self._table.hover_selection
def set_hover_selection(self, value):
- self._hover_selection = value
+ self._table.hover_selection = value
hover_selection = gobject.property(type=object,
getter=get_hover_selection, setter=set_hover_selection)
@@ -144,52 +270,105 @@ class TableView(gtk.Viewport):
frame = self._get_frame()
return ((frame[0],), (frame[1],))
- def do_size_allocate(self, alloc):
- gtk.Viewport.do_size_allocate(self, alloc)
- self._full_height = alloc.height + 100
- self._table.set_size_request(-1, self._full_height)
+ def do_set_scroll_adjustments(self, hadjustment, vadjustment):
+ if vadjustment is None or vadjustment == self._full_adjustment:
+ return
+ if self._full_adjustment is not None:
+ self._full_adjustment.disconnect_by_func(
+ self.__adjustment_value_changed)
+ self._full_adjustment = vadjustment
+ self._full_adjustment.connect('value-changed',
+ self.__adjustment_value_changed)
self._setup_adjustment()
+ def do_size_allocate(self, allocation):
+ self.child.size_allocate(allocation)
+ self._cell_height = allocation.height / self._rows
+ self._setup_adjustment()
+
+ def do_size_request(self, requisition):
+ requisition.width, requisition.height = self.child.size_request()
+
def _fillin_cell(self, canvas, cell):
+ if self._table.selected_cell == cell and cell.get_visible():
+ bg_color = COLOR_SELECTED
+ else:
+ bg_color = COLOR_BACKGROUND
+ canvas.root.props.background_color = bg_color.get_int()
+
if cell.row is None:
cell.set_visible(False)
else:
cell.fillin()
cell.set_visible(True)
- bg_color = COLOR_BACKGROUND
- if self._selected_cell == cell:
- if cell.get_visible():
- bg_color = COLOR_SELECTED
canvas.root.props.background_color = bg_color.get_int()
def _setup_adjustment(self):
- if self._full_adjustment is None or self._full_height == 0:
+ if self._full_adjustment is None or self._cell_height == 0:
return
- adj = self._full_adjustment.props
+ adj = self._full_adjustment
if self._model is None:
adj.upper = 0
adj.value = 0
return
- if self._cols == 0:
- adj.upper = 0
- else:
- count = self._model.iter_n_children(None)
- adj.upper = int(math.ceil(float(count) / self._cols))
+ count = self._model.iter_n_children(None)
- adj.value = min(adj.value, adj.upper - self._rows)
- adj.page_size = self._rows
- adj.page_increment = self._rows
+ adj.upper = max(0, math.ceil(float(count) / self._cols) * \
+ self._cell_height)
+ adj.value = min(adj.value, adj.upper)
+ adj.page_size = self._cell_height * self._rows
+ adj.page_increment = adj.page_size
self._full_adjustment.changed()
- self.__adjustment_value_changed(self._full_adjustment)
+ self.__adjustment_value_changed(self._full_adjustment, force=True)
def _get_frame(self):
- return (int(self._full_adjustment.props.value) * self._cols,
- (int(self._full_adjustment.props.value) + self._rows) * self._cols - 1)
+ adj = self._full_adjustment
+ return (int(adj.value / self._cell_height) * self._cols,
+ (int(adj.value / self._cell_height) + self._rows) * \
+ self._cols - 1)
+
+ def __adjustment_value_changed(self, adjustment, force=False):
+ if self._last_adjustment == int(adjustment.value):
+ return
+ self._last_adjustment = int(adjustment.value)
+
+ cell_row = int(adjustment.props.value) / self._cell_height
+ cell_num = cell_row * self._cols
+
+ smooth_adj = self.child.props.vadjustment
+ smooth_adj_value = int(min(smooth_adj.upper,
+ int(adjustment.props.value) - (cell_row * self._cell_height)))
+
+ if cell_num == self._top_cell and not force:
+ smooth_adj.value = smooth_adj_value
+ smooth_adj.value_changed()
+ return
+ self._top_cell = cell_num
+
+ if self._model is not None:
+ count = self._model.iter_n_children(None)
+ else:
+ count = 0
+
+ for y in range(self._rows + 1):
+ for x in range(self._cols):
+ canvas, cell = self._cells[y][x]
+
+ cell.row = None
+ if cell_num < count:
+ cell.row = self._model.get_row((cell_num,),
+ self._get_frame())
+
+ self._fillin_cell(canvas, cell)
+ cell_num += 1
+
+ smooth_adj.value = smooth_adj_value
+ smooth_adj.value_changed()
def __row_changed_cb(self, model, path, iter):
range = self._get_frame()
@@ -207,58 +386,35 @@ class TableView(gtk.Viewport):
self._setup_adjustment()
def __key_press_event_cb(self, widget, event):
- if self._full_adjustment is None or self._full_height == 0:
+ if self._full_adjustment is None or self._cell_height == 0:
return
adj = self._full_adjustment.props
- uplimit = adj.upper - self._rows
+ page = self._rows * self._cell_height
+ uplimit = adj.upper - page
if event.keyval == gtk.keysyms.Up:
- adj.value -= 1
+ adj.value -= self._cell_height
+
elif event.keyval == gtk.keysyms.Down:
- if adj.value + 1 <= uplimit:
- adj.value += 1
+ adj.value += min(uplimit - adj.value, self._cell_height)
+
elif event.keyval in (gtk.keysyms.Page_Up, gtk.keysyms.KP_Page_Up):
- adj.value -= self._rows
+ adj.value -= min(adj.value, page)
+
elif event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.KP_Page_Down):
- if adj.value + self._rows <= uplimit:
- adj.value += self._rows
+ adj.value += min(uplimit - adj.value, page)
+
elif event.keyval in (gtk.keysyms.Home, gtk.keysyms.KP_Home):
adj.value = 0
+
elif event.keyval in (gtk.keysyms.End, gtk.keysyms.KP_End):
adj.value = uplimit
+
else:
return False
return True
- def __button_release_event_cb(self, widget, event, cell):
- cell.on_release(widget, event)
-
- def __enter_notify_event_cb(self, canvas, event, cell):
- if cell.get_visible():
- canvas.root.props.background_color = COLOR_SELECTED.get_int()
- self._selected_cell = cell
-
- def __leave_notify_event_cb(self, canvas, event):
- canvas.root.props.background_color = COLOR_BACKGROUND.get_int()
- self._selected_cell = None
-
- def __adjustment_value_changed(self, adjustment):
- if self._model:
- count = self._model.iter_n_children(None)
- else:
- count = 0
- cell_num = int(adjustment.props.value) * self._cols
-
- for y in range(self._rows):
- for x in range(self._cols):
- canvas, cell = self._cells[y][x]
-
- cell.row = None
- if cell_num < count:
- cell.row = self._model.get_row((cell_num,),
- self._get_frame())
-
- self._fillin_cell(canvas, cell)
- cell_num += 1
+TableView.set_set_scroll_adjustments_signal('set-scroll-adjustments')
+_SmoothTable.set_set_scroll_adjustments_signal('set-scroll-adjustments')
diff --git a/src/jarabe/journal/thumbsview.py b/src/jarabe/journal/thumbsview.py
index 4dca8df..920bf2c 100644
--- a/src/jarabe/journal/thumbsview.py
+++ b/src/jarabe/journal/thumbsview.py
@@ -21,14 +21,19 @@ import hippo
from jarabe.journal.browse.lazymodel import Source
from jarabe.journal.browse.tableview import TableView, TableCell
+from jarabe.journal.browse.source import *
class ThumbsCell(TableCell, hippo.CanvasBox):
def __init__(self):
TableCell.__init__(self)
hippo.CanvasBox.__init__(self, orientation=hippo.ORIENTATION_VERTICAL)
- label = hippo.CanvasWidget(widget=gtk.Button('!!!'))
- self.append(label)
+ self.label = hippo.CanvasText(
+ size_mode=hippo.CANVAS_SIZE_ELLIPSIZE_END)
+ self.append(self.label)
+
+ def fillin(self):
+ self.label.props.text = self.row[FIELD_TITLE] or ''
class ThumbsView(TableView):
__gsignals__ = {