From 73b171228231dbf04f74df1d6ece7a9694240947 Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Tue, 28 Apr 2009 09:43:16 +1000 Subject: [PATCH] Starting a custom cell for the messages --- mitterlib/ui/ui_pygtk.py | 125 +++++++++++++++++++++++++++++++++++---- 1 file changed, 112 insertions(+), 13 deletions(-) diff --git a/mitterlib/ui/ui_pygtk.py b/mitterlib/ui/ui_pygtk.py index 89d9004..178bc20 100644 --- a/mitterlib/ui/ui_pygtk.py +++ b/mitterlib/ui/ui_pygtk.py @@ -99,7 +99,7 @@ class _WorkerThread(threading.Thread, _IdleObject): def run(self): # call the function - _log.debug('Thread %s calling %s', self.ident, str(self._function)) + _log.debug('Thread %s calling %s', self.name, str(self._function)) args = self._args kwargs = self._kwargs @@ -183,6 +183,76 @@ class _ThreadManager(object): self._thread_id += 1 return +# ---------------------------------------------------------------------- +# Custom cell renderer +# ---------------------------------------------------------------------- +class CellRendererNetworkData(gtk.GenericCellrenderer): + """A customized cell renderer for messages.""" + + __gproperties__ = { + 'message': (gobject.TYPE_PYOBJECT, + 'message', + 'A NetworkData object to be rendered', + '', + gobject.PARAM_WRITABLE) + } + + def __init__(self): + super(CellrendererNetworkData, self).__init__(self) + self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) + return + + def on_render(self, window, widget, bg_area, cell_area, exp_area, flags): + """The render() method invokes the virtual render function of the + gtk.CellRenderer. The three passed-in rectangles are areas of window. + Most renderers will draw within cell_area; the xalign, yalign, xpad, + and ypad properties of the gtk.CellRenderer should be honored with + respect to cell_area. background_area includes the blank space around + the cell, and also the area containing the tree expander; so the + background_area rectangles for all cells tile to cover the entire + window. expose_area is a clip rectangle. + + The flags value is one of: gtk.CELL_RENDERER_SELECTED, + gtk.CELL_RENDERER_PRELIT, gtk.CELL_RENDERER_INSENSITIVE or + gtk.CELL_RENDERER_SORTED""" + + layout = self.get_layout(widget) + + if flags & gtk.CELL_RENDERER_SELECTED: + if widget.get_property('has-focus'): + state = gtk.STATE_SELECTED + else: + satte = gtk.STATE_ACTIVE + else: + state = gtk.STATE_NORMAL + + widget.style.paint_layout( + window, + state, + True, + cell_area, + widget, + 'foo', + cell_area.x + x_offset, + cell_area.y + y_offset, + layout + ) + return + + def on_get_size(sel, widget, cell_area): + """The get_size() method obtains the width and height needed to render + the cell. These values are returned as part of a tuple containing the + x_offset, y_offset, width and height. get_size() is used by view + widgets to determine the appropriate size for the cell_area to be + passed to the gtk.CellRenderer.render() method. If cell_area is not + None, the x and y offsets of the cell relative to this location are + returned. Please note that the values set in the returned width and + height, as well as those in x_offset and y_offset are inclusive of the + xpad and ypad properties.""" + return (x_offset, y_offset, width, height) + +gobject.type_register(CellRendererNetworkData) + # ---------------------------------------------------------------------- # Mitter interface object # ---------------------------------------------------------------------- @@ -230,7 +300,7 @@ class Interface(object): main_window.connect('destroy', self._quit_app) main_window.connect('delete-event', self._quit_app) - main_window.connect('size-request', self._window_resize) + main_window.connect('size-request', self._grid_resize) grid = self._create_grid() (menu, toolbar, accelerators) = self._create_menu_and_toolbar() @@ -263,19 +333,31 @@ class Interface(object): user_renderer = gtk.CellRendererPixbuf() user_column = gtk.TreeViewColumn('User', user_renderer) + user_column.set_fixed_width(48) # avatar size (we resize to 48x48) + user_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) user_column.set_cell_data_func(user_renderer, self._cell_renderer_user) - self._grid.append_column(user_column) message_renderer = gtk.CellRendererText() message_renderer.set_property('wrap-mode', gtk.WRAP_WORD) message_renderer.set_property('wrap-width', 200) - message_renderer.set_property('width', 10) - message_column = gtk.TreeViewColumn('Message', message_renderer) message_column.set_cell_data_func(message_renderer, self._cell_renderer_message) + + options_renderer = gtk.CellRendererPixbuf() + options_renderer.set_fixed_size(16, 16) + options_column = gtk.TreeViewColumn('Options', options_renderer) + options_column.set_cell_data_func(options_renderer, + self._cell_renderer_options) + #options_column.set_fixed_width(16) # icon size + #options_column.set_max_width(16) + #options_column.set_expand(False) + #options_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + + self._grid.append_column(user_column) + self._grid.append_column(options_column) self._grid.append_column(message_column) self._grid.set_resize_mode(gtk.RESIZE_IMMEDIATE) @@ -498,14 +580,13 @@ class Interface(object): # unescape escaped entities that pango is not okay with message = re.sub(r'&', r'&', message) - #_log.debug('Rendering message: %s', message) + _log.debug('Rendering message: %s', message) # highlight URLs mask = r'\1' % ( self._options[self.NAMESPACE]['link_colour']) message = URL_RE.sub(mask, message) - # use a different highlight for the current user #message = re.sub(r'(@'+self.twitter.username+')', # r'\1', @@ -517,6 +598,13 @@ class Interface(object): return + def _cell_renderer_options(self, column, cell, store, position): + """Callback for the options renderer. Adds the delete icon if the + message belongs to the user or reply if not.""" + data = store.get_value(position, 0) + cell.set_property('pixbuf', self._reply_pixbuf) + return + # ------------------------------------------------------------ # Helper functions # ------------------------------------------------------------ @@ -577,26 +665,34 @@ class Interface(object): gtk.main_quit() return - def _window_resize(self, widget, request, data=None): + def _grid_resize(self, widget, allocation, data=None): """Called when the window is resized. We use it to set the proper word-wrapping in the message column.""" - (width, height) = widget.get_size() model = self._grid.get_model() - if len(model) == 0: # nothing in the list, so we don't have what to set proper word # wrapping return - column = self._grid.get_column(1) + _log.debug('Widget size: %d', allocation.width) + + column = self._grid.get_column(2) iter = model.get_iter_first() path = model.get_path(iter) - column_rectangle = self._grid.get_cell_area(path, column) + cell_rectangle = self._grid.get_cell_area(path, column) + # x_padding + + # focus-line-width + focus_line_width = self._grid.style_get_property('focus-line-width') + #rectangle_width = column_rectangle.width + + width = cell_rectangle.width - focus_line_width for renderer in column.get_cell_renderers(): - renderer.set_property('wrap-width', column_rectangle.width) + renderer.set_property('wrap-width', width) + renderer.set_property('width', width) while iter: path = model.get_path(iter) @@ -711,6 +807,9 @@ class Interface(object): # Load images self._app_icon = find_image('mitter.png') self._app_icon_alert = find_image('mitter-new.png') + self._reply_pixbuf = gtk.gdk.pixbuf_new_from_file( + find_image('reply.png')) + #self._delete_icon = find_image('icon_trash.gif') unknown_pixbuf = find_image('unknown.png') if unknown_pixbuf: