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-21 20:36:41 (GMT)
committer Aleksey Lim <alsroot@member.fsf.org>2009-08-25 15:47:56 (GMT)
commit8221d89c377b0644f302e9fc463296733a7b536d (patch)
tree6d77f95d964537aad2185b713e95adb03378caa2 /src
parent8d6a09f140ee167c312668215546d085705f9127 (diff)
Utilize SmoothTable in TableView
Diffstat (limited to 'src')
-rw-r--r--src/jarabe/journal/browse/smoothtable.py111
-rw-r--r--src/jarabe/journal/browse/tableview.py394
2 files changed, 162 insertions, 343 deletions
diff --git a/src/jarabe/journal/browse/smoothtable.py b/src/jarabe/journal/browse/smoothtable.py
index 8962a11..c797745 100644
--- a/src/jarabe/journal/browse/smoothtable.py
+++ b/src/jarabe/journal/browse/smoothtable.py
@@ -28,7 +28,7 @@ class SmoothTable(gtk.Container):
[gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]),
}
- def __init__(self, rows, columns, new_widget):
+ def __init__(self, rows, columns, new_cell, fill_in):
assert(rows and columns)
self._rows = []
@@ -39,20 +39,22 @@ class SmoothTable(gtk.Container):
self._cell_height = 0
self._reordered = None
self._last_allocation = None
+ self._fill_in = fill_in
gtk.Container.__init__(self)
- cell_no = 0
for y in range(rows + 2):
row = []
for x in range(columns):
- cell = new_widget()
+ cell = new_cell()
+ cell.show()
cell.set_parent(self)
cell.size_allocate(gtk.gdk.Rectangle(-1, -1))
- cell_no += 1
row.append(cell)
self._rows.append(row)
+ self.connect('key-press-event', self.__key_press_event_cb)
+
def get_columns(self):
return len(self._rows[0])
@@ -63,15 +65,19 @@ class SmoothTable(gtk.Container):
rows = property(get_rows)
- def get_head(self):
- if self._adj is None:
- return 0
- return int(self._adj.value) - int(self._adj.value) % self._cell_height
+ def get_frame(self):
+ if self._adj is None or self._cell_height == 0:
+ return (0, 0)
+ top = int(self._adj.value / self._cell_height)
+ return (top * self.columns, (top + self.rows) * self.columns - 1)
+
+ frame = property(get_frame)
- head = property(get_head)
+ def get_bin_rows(self):
+ return self._bin_rows
- def set_count(self, count):
- self._bin_rows = max(0, math.ceil(float(count) / len(self._rows[0])))
+ def set_bin_rows(self, bin_rows):
+ self._bin_rows = bin_rows
if self._adj is not None:
self._setup_adjustment(force=True)
@@ -79,6 +85,14 @@ class SmoothTable(gtk.Container):
self._bin_window.resize(self.allocation.width,
int(self._adj.upper))
+ bin_rows = property(get_bin_rows, set_bin_rows)
+
+ def goto(self, row):
+ if self._adj is None:
+ return
+ self._adj.props.value = row * self._cell_height
+ self._adj.value_changed()
+
def do_realize(self):
self.set_flags(gtk.REALIZED)
@@ -208,9 +222,10 @@ class SmoothTable(gtk.Container):
def _allocate_row(self, row, cell_y):
cell_x = 0
cell_no = cell_y / self._cell_height * self.columns
+ cell_row = cell_y / self._cell_height
- for cell in row:
- self.emit('fill-in', cell, cell_no)
+ for cell_column, cell in enumerate(row):
+ self._fill_in(cell, cell_row, cell_column)
callocation = gtk.gdk.Rectangle(cell_x, cell_y)
callocation.width = self.allocation.width / self.columns
@@ -220,8 +235,24 @@ class SmoothTable(gtk.Container):
cell_x += callocation.width
cell_no += 1
+ def _get_head(self):
+ if self._adj is None:
+ return 0
+ return int(self._adj.value) - int(self._adj.value) % self._cell_height
+
def __adjustment_value_changed_cb(self, sender=None):
- if not self.flags() & gtk.REALIZED:
+ if not self.flags() & gtk.REALIZED or self._cell_height == 0:
+ return
+
+ if self._adj.value < 0:
+ self._adj.value = 0
+ self._adj.value_changed()
+ return
+
+ bottom = self._adj.upper - (self.rows * self._cell_height)
+ if self._adj.value > bottom:
+ self._adj.value = bottom
+ self._adj.value_changed()
return
spare_rows = []
@@ -248,8 +279,8 @@ class SmoothTable(gtk.Container):
else:
bisect.insort_right(visible_rows, IndexedRow(row))
- if not visible_rows or \
- len(visible_rows) < self.rows + (self.head != visible_rows[0]):
+ if not visible_rows or len(visible_rows) < self.rows + \
+ (self._get_head() != visible_rows[0]):
self._reordered = self.allocation
def insert_spare_row(cell_y, end_y):
@@ -261,7 +292,7 @@ class SmoothTable(gtk.Container):
self._allocate_row(row, cell_y)
cell_y = cell_y + self._cell_height
- cell_y = self.head
+ cell_y = self._get_head()
for i in visible_rows:
insert_spare_row(cell_y, i.row[0].allocation.y)
cell_y = i.row[0].allocation.y + i.row[0].allocation.height
@@ -270,21 +301,57 @@ class SmoothTable(gtk.Container):
self._bin_window.move(0, int(-self._adj.value))
self.window.process_updates(True)
+ def __key_press_event_cb(self, widget, event):
+ if self._adj is None or self._cell_height == 0:
+ return
+
+ page = self.rows * self._cell_height
+ uplimit = self._adj.upper - page
+
+ if event.keyval == gtk.keysyms.Up:
+ self._adj.value -= self._cell_height
+
+ elif event.keyval == gtk.keysyms.Down:
+ self._adj.value += min(uplimit - self._adj.value, self._cell_height)
+
+ elif event.keyval in (gtk.keysyms.Page_Up, gtk.keysyms.KP_Page_Up):
+ self._adj.value -= min(self._adj.value, page)
+
+ elif event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.KP_Page_Down):
+ self._adj.value += min(uplimit - self._adj.value, page)
+
+ elif event.keyval in (gtk.keysyms.Home, gtk.keysyms.KP_Home):
+ self._adj.value = 0
+
+ elif event.keyval in (gtk.keysyms.End, gtk.keysyms.KP_End):
+ self._adj.value = uplimit
+
+ else:
+ return False
+
+ return True
+
SmoothTable.set_set_scroll_adjustments_signal('set-scroll-adjustments')
if __name__ == '__main__':
+ import random
+
window = gtk.Window()
scrolled = gtk.ScrolledWindow()
scrolled.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
window.add(scrolled)
- def cb(sender, button, offset):
- button.props.label = str(offset)
- table = SmoothTable(3, 3, gtk.Button)
- table.connect('fill-in', cb)
- table.set_count(100)
+ def fill_in(cell, row, column):
+ cell.props.label = '%s:%s' % (row, column)
+ table = SmoothTable(3, 3, gtk.Button, fill_in)
+ table.bin_rows = 100
scrolled.add(table)
+ for row in table._rows:
+ for cell in row:
+ cell.connect('clicked',
+ lambda button: table.goto(random.randint(0, 100)))
+
window.show_all()
gtk.main()
diff --git a/src/jarabe/journal/browse/tableview.py b/src/jarabe/journal/browse/tableview.py
index 4aa6697..235d3b3 100644
--- a/src/jarabe/journal/browse/tableview.py
+++ b/src/jarabe/journal/browse/tableview.py
@@ -22,6 +22,7 @@ import logging
from sugar.graphics import style
from sugar.graphics.roundbox import CanvasRoundBox
+from jarabe.journal.browse.smoothtable import SmoothTable
COLOR_BACKGROUND = style.COLOR_WHITE
COLOR_SELECTED = style.COLOR_TEXT_FIELD_GREY
@@ -36,207 +37,20 @@ class TableCell:
def on_release(self, widget, event):
pass
-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._heigth = 0
- self.selected_cell = None
- self.hover_selection = False
-
- gtk.Bin.__init__(self)
-
- 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,
- COLOR_BACKGROUND.get_gdk_color())
-
- sel_box = CanvasRoundBox()
- sel_box.props.border_color = COLOR_BACKGROUND.get_int()
- canvas.set_root(sel_box)
- canvas.root = sel_box
-
- cell = cell_class()
- sel_box.append(cell, hippo.PACK_EXPAND)
-
- 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)
-
- table.attach(canvas, x, x + 1, y, y + 1,
- gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
- cells[y][x] = (canvas, cell)
+class TableView(SmoothTable):
+ def __init__(self, cell_class, rows, columns):
+ SmoothTable.__init__(self, rows, columns,
+ lambda: self._create_cell(cell_class), self._fill_in)
- 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(self._table)
- self.add(smooth_box)
-
- self.connect('key-press-event', self.__key_press_event_cb)
-
- def get_size(self):
- return (self._cols, self._rows)
+ self._hover_selection = False
+ self._selected_cell = None
def get_cursor(self):
- frame = self._get_frame()
- return (frame[0],)
+ return (self.frame[0],)
def set_cursor(self, cursor):
- if self._full_adjustment is None or self._cell_height == 0:
- return
- self._full_adjustment.props.value = self._cell_height * cursor
- self._full_adjustment.changed()
+ self.goto(cursor)
def get_model(self):
return self._model
@@ -252,170 +66,108 @@ class TableView(gtk.Bin):
self._model.connect('row-changed', self.__row_changed_cb)
self._model.connect('row-inserted', self.__table_resized_cb)
self._model.connect('row-deleted', self.__table_resized_cb)
- self._setup_adjustment()
+ self.bin_rows = self._model.iter_n_children(None) / self.columns
model = gobject.property(type=object,
getter=get_model, setter=set_model)
def get_hover_selection(self):
- return self._table.hover_selection
+ return self._hover_selection
def set_hover_selection(self, value):
- self._table.hover_selection = value
+ self._hover_selection = value
hover_selection = gobject.property(type=object,
getter=get_hover_selection, setter=set_hover_selection)
def get_visible_range(self):
- frame = self._get_frame()
- return ((frame[0],), (frame[1],))
-
- 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)
+ return ((self.frame[0],), (self.frame[1],))
- canvas.root.props.background_color = bg_color.get_int()
+ def _create_cell(self, cell_class):
+ canvas = hippo.Canvas()
+ canvas.show()
+ canvas.modify_bg(gtk.STATE_NORMAL, COLOR_BACKGROUND.get_gdk_color())
- def _setup_adjustment(self):
- if self._full_adjustment is None or self._cell_height == 0:
- return
+ sel_box = CanvasRoundBox()
+ sel_box.props.border_color = COLOR_BACKGROUND.get_int()
+ canvas.set_root(sel_box)
- adj = self._full_adjustment
+ cell = cell_class()
+ sel_box.append(cell, hippo.PACK_EXPAND)
- if self._model is None:
- adj.upper = 0
- adj.value = 0
- return
+ 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)
- count = self._model.iter_n_children(None)
+ canvas.table_view_cell_sel_box = sel_box
+ canvas.table_view_cell = cell
- 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()
+ return canvas
- self.__adjustment_value_changed(self._full_adjustment, force=True)
+ def _fill_in(self, canvas, y, x, row=None):
- def _get_frame(self):
- adj = self._full_adjustment
- return (int(adj.value / self._cell_height) * self._cols,
- (int(adj.value / self._cell_height) + self._rows + 1) * \
- self._cols - 1)
+ cell = canvas.table_view_cell
+ sel_box = canvas.table_view_cell_sel_box
- def __adjustment_value_changed(self, adjustment, force=False):
- if self._last_adjustment == int(adjustment.value):
- return
- self._last_adjustment = int(adjustment.value)
+ if self._selected_cell == cell and cell.get_visible():
+ bg_color = COLOR_SELECTED
+ else:
+ bg_color = COLOR_BACKGROUND
+ sel_box.props.background_color = bg_color.get_int()
- cell_row = int(adjustment.props.value) / self._cell_height
- cell_num = cell_row * self._cols
+ cell.row = row
- 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.row is None:
+ cell_num = y * self.columns + x
- 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 cell_num < self._model.iter_n_children(None):
+ row = self._model.get_row((cell_num,), self.frame)
+ if row != False:
+ cell.row = row
- if self._model is not None:
- count = self._model.iter_n_children(None)
+ if cell.row is None:
+ cell.set_visible(False)
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:
- row = self._model.get_row((cell_num,), self._get_frame())
- if row != False:
- cell.row = row
-
- self._fillin_cell(canvas, cell)
- cell_num += 1
+ cell.fillin()
+ cell.set_visible(True)
- smooth_adj.value = smooth_adj_value
- smooth_adj.value_changed()
+ def __button_release_event_cb(self, widget, event, cell):
+ cell.on_release(widget, event)
- def __row_changed_cb(self, model, path, iter):
- range = self._get_frame()
- if path[0] < range[0] or path[0] > range[1]:
+ def __enter_notify_event_cb(self, canvas, event, cell):
+ if not self.hover_selection:
return
- y = (path[0] - range[0]) / self._cols
- x = (path[0] - range[0]) % self._cols
-
- canvas, cell = self._cells[y][x]
- cell.row = self._model.get_row(path)
- self._fillin_cell(canvas, cell)
+ if cell.get_visible():
+ sel_box = canvas.table_view_cell_sel_box
+ sel_box.props.background_color = COLOR_SELECTED.get_int()
- def __table_resized_cb(self, model=None, path=None, iter=None):
- self._setup_adjustment()
+ self._selected_cell = cell
- def __key_press_event_cb(self, widget, event):
- if self._full_adjustment is None or self._cell_height == 0:
+ def __leave_notify_event_cb(self, canvas, event):
+ if not self.hover_selection:
return
- adj = self._full_adjustment.props
- page = self._rows * self._cell_height
- uplimit = adj.upper - page
-
- if event.keyval == gtk.keysyms.Up:
- adj.value -= self._cell_height
+ sel_box = canvas.table_view_cell_sel_box
+ sel_box.props.background_color = COLOR_BACKGROUND.get_int()
- elif event.keyval == gtk.keysyms.Down:
- adj.value += min(uplimit - adj.value, self._cell_height)
+ self._selected_cell = None
- elif event.keyval in (gtk.keysyms.Page_Up, gtk.keysyms.KP_Page_Up):
- adj.value -= min(adj.value, page)
-
- elif event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.KP_Page_Down):
- adj.value += min(uplimit - adj.value, page)
+ def __row_changed_cb(self, model, path, iter):
+ range = self.frame
+ if path[0] < range[0] or path[0] > range[1]:
+ return
- elif event.keyval in (gtk.keysyms.Home, gtk.keysyms.KP_Home):
- adj.value = 0
+ y = (path[0] - range[0]) / self.columns
+ x = (path[0] - range[0]) % self.columns
- elif event.keyval in (gtk.keysyms.End, gtk.keysyms.KP_End):
- adj.value = uplimit
+ from jarabe.journal.objectmodel import Source
- else:
- return False
+ canvas = self._rows[y][x]
+ row = self._model.get_row(path)
- return True
+ self._fill_in(canvas, y, x, row)
-TableView.set_set_scroll_adjustments_signal('set-scroll-adjustments')
-_SmoothTable.set_set_scroll_adjustments_signal('set-scroll-adjustments')
+ def __table_resized_cb(self, model=None, path=None, iter=None):
+ self.bin_rows = self._model.iter_n_children(None) / self.columns