From 8221d89c377b0644f302e9fc463296733a7b536d Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Fri, 21 Aug 2009 20:36:41 +0000 Subject: Utilize SmoothTable in TableView --- (limited to 'src') 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 -- cgit v0.9.1