[pygtk] re : adding buttons to ListStore rows

Laurent G. lauranger at free.fr
Sat Aug 9 04:53:40 WST 2008


Hi
I don't know if you can get anything useful from what I send but here is 
my class for color and toggle buttons I wrote for my gimp plugin.

Hth
Regards

Laurent G.


class ColorBtnCellRenderer(gtk.GenericCellRenderer):
     __gsignals__ = {
          'color-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
                     (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT))
      }
     def __init__(self):
         gtk.GenericCellRenderer.__init__(self)
         self.__gobject_init__()
         self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)

         self.xpad = 4; self.ypad = 3
         self.xalign = 0.5; self.yalign = 0.5
         self.gc  = None
         self.color = gtk.gdk.Color(100,100,100)
         self.dialog = gtk.ColorSelectionDialog('')
         self.active_area = None
         self.sig_deac = None

     def do_set_property(self, pspec, value):
         setattr(self, pspec.name, value)
     def do_get_property(self, pspec):
         return getattr(self, pspec.name)

     def on_render(self, window, widget, background_area,
                   cell_area, expose_area, flags):
         if not isinstance(window, gtk.gdk.Window):
             print "not GdkWindow"
             return
         state = gtk.STATE_NORMAL
         if flags & 128:
             b = bool(flags & 64)
         else:
             b = not cmp_rects(self.active_area, cell_area)
         shadow = gtk.SHADOW_OUT if b else gtk.SHADOW_IN
         x_offset, y_offset, width, height = self.on_get_size(widget, 
cell_area)
         widget.style.paint_box(window,
                 state, shadow,
                 cell_area, widget, None,
                 cell_area.x,
                 cell_area.y,
                 cell_area.width,  cell_area.height)
         if self.gc is None:
             self.bg = window.get_colormap().alloc_color(0xffff, 0, 0)
             self.fg = window.get_colormap().alloc_color(0, 0xffff, 0)
             self.gc = gtk.gdk.GC(window, self.fg, self.bg)
         self.gc.set_rgb_fg_color(self.color)
         window.draw_rectangle(self.gc, True, cell_area.x+x_offset, 
cell_area.y+ y_offset, width, height)

     def on_get_size(self, widget, cell_area):
         if cell_area:
             calc_width = cell_area.width - 2*self.xpad
             calc_height = cell_area.height - 2*self.ypad
             x_offset = int(self.xalign * (cell_area.width - calc_width))
             x_offset = max(x_offset, 0)
             y_offset = int(self.yalign * (cell_area.height - calc_height))
             y_offset = max(y_offset, 0)
         else:
             x_offset = 0
             y_offset = 0
             calc_width = 20
             calc_height = 16
         return x_offset, y_offset, calc_width, calc_height

     def on_activate(self, event, widget, path, background_area, 
cell_area, flags):
         if event and event.type == gtk.gdk.BUTTON_PRESS:
             self.edit_color = self.color
             self.sig_deac = widget.connect('button-release-event', 
self.on_deactivate, cell_area, path)
             self.sig_move = widget.connect('motion-notify-event', 
self.on_mouse_move, cell_area, path)
         self.active_area = cell_area
         self.on_render(widget.get_bin_window(), widget, None, 
cell_area, None, 3 << 6)

     def on_deactivate(self, w, e, cell_area, path):
         if self.sig_deac is not None: w.disconnect(self.sig_deac)
         if self.sig_move is not None: w.disconnect(self.sig_move)
         if ( cell_area.x <= int(e.x) <= cell_area.x + cell_area.width ) \
                 and ( cell_area.y <= int(e.y) <= cell_area.y + 
cell_area.height):
             self.dialog.colorsel.set_property('current-color', 
self.edit_color)
             ret = self.dialog.run()
             if ret == 
self.dialog.get_response_for_widget(self.dialog.ok_button):
                 c = self.dialog.colorsel.get_property('current-color')
                 #self.edit_color = c
                 self.emit('color-changed', path, c)
             self.color = self.edit_color
             self.dialog.hide()
         self.active_area = None
         self.on_render(w.get_bin_window(), w, None, cell_area, None, 0)

     def on_mouse_move(self, w, e, cell_area, path):
         inside = 2 + int(cell_area.x <= e.x < cell_area.x + 
cell_area.width \
                 and cell_area.y <= e.y < cell_area.y + cell_area.height)
         self.color = self.edit_color
         self.on_render(w.get_bin_window(), w, None, cell_area, None, 
inside << 6)

gobject.type_register(ColorBtnCellRenderer)

class ButtonCellRenderer(gtk.GenericCellRenderer):
     __gsignals__ = {
          'toggled': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
                     (gobject.TYPE_STRING,))
      }
     def __init__(self):
         gtk.GenericCellRenderer.__init__(self)
         self.__gobject_init__()
         self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE)

         self.xpad = 1; self.ypad = 0
         self.xalign = 0.5; self.yalign = 0.5
         self.active_area = None
         self.toggled = False
         self.pango_l  = None
         self.text = ""

     def do_set_property(self, pspec, value):
         print "set prop ", pspec.name
         setattr(self, pspec.name, value)
     def do_get_property(self, pspec):
         print "get prop ", pspec.name
         return getattr(self, pspec.name)

     def on_render(self, window, widget, background_area,
                   cell_area, expose_area, flags):
         if not isinstance(window, gtk.gdk.Window):
         #if not isinstance(window, gtk.gdk.Drawable):
             return
         if self.get_property('mode') != gtk.CELL_RENDERER_MODE_ACTIVATABLE:
             state = gtk.STATE_INSENSITIVE
         else:
             state = gtk.STATE_NORMAL
         concerned = cmp_rects(self.active_area, cell_area)
         changing = self.active_area is not None
         shadow = gtk.SHADOW_IN if (concerned and changing) ^ 
self.toggled else gtk.SHADOW_OUT
         x_offset, y_offset, width, height = self.on_get_size(widget, 
cell_area)
         widget.style.paint_box(window,
                 state, shadow,
                 cell_area, widget, None,
                 cell_area.x + x_offset,
                 cell_area.y + y_offset,
                 width,  height)
         if self.pango_l is None:
             context = widget.create_pango_context()
             self.pango_l = pango.Layout(context)
         self.pango_l.set_text(self.text)
         w, h = self.pango_l.get_pixel_size()
         widget.style.paint_layout(window, state, True,
                 cell_area, widget, None,
                 cell_area.x + x_offset + (width -w)/2,
                 cell_area.y + y_offset + (height -h)/2,
                 self.pango_l)

     def on_get_size(self, widget, cell_area):
         if cell_area:
             calc_width = cell_area.width - 2*self.xpad
             calc_height = cell_area.height - 2*self.ypad
             if calc_width < calc_height:
                 calc_height = calc_width
             else:
                 calc_width = calc_height
             x_offset = int(self.xalign * (cell_area.width - calc_width))
             x_offset = max(x_offset, 0)
             y_offset = int(self.yalign * (cell_area.height - calc_height))
             y_offset = max(y_offset, 0)
         else:
             x_offset = 0
             y_offset = 0
             calc_width = 20
             calc_height = 16
         return x_offset, y_offset, calc_width, calc_height

     def on_activate(self, event, widget, path, background_area, 
cell_area, flags):
         self.sig_deac = widget.connect('button-release-event', 
self.on_deactivate, cell_area, path)
         self.active_area = cell_area
         self.toggled = not self.toggled

     def on_deactivate(self, w, e, cell_area, path):
         w.disconnect(self.sig_deac)
         if ( cell_area.x <= int(e.x) <= cell_area.x + cell_area.width ) \
                 and ( cell_area.y <= int(e.y) <= cell_area.y + 
cell_area.height):
             self.emit('toggled', path)
         self.active_area = None
         self.on_render(w.get_bin_window(), w, None, cell_area, None, 0)



More information about the pygtk mailing list