Re: A custom cellrenderer for a bixbuf with text



On Thursday, April 29, 2004, at 01:48 PM, Florian Schaefer wrote:

thanks to your help in the thread "pixbuf and text in one column" I've been able to produce something that comes quite close to what I want. My result so far is attached.

i tried it -- a window pops up and immediately explodes, with the message

  The program 'cellrenderer.pl' received an X Window System error.
  This probably reflects a bug in the program.
  The error was 'BadMatch (invalid parameter attributes)'.
    (Details: serial 174 error_code 8 request_code 72 minor_code 0)
(Note to programmers: normally, X errors are reported asynchronously;
     that is, you will receive the error a while after causing it.
     To debug your program, run it with the --sync command line
     option to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)

  (not a message from the bindings)

in your RENDER override, you're creating a GC to render the pixbuf to the window. specifically, you're creating a new GC, using a new Pixmap. this is bad for three reasons:

1) creating Pixmaps and GCs requires talking to the server, so you have two extra round trips for each cell rendering (and there are a lot of them!). it's also really wasteful -- you allocate these resources and then get rid of them, in rapid succession. in general you'd want to preallocate and cache these resources.

2) you just created a brand new Pixmap, without choosing a colormap. the point in supplying a drawable to the GC constructor is that you create a GC which uses the same colormap and visual as the things on which it's supposed to work. the new Pixmap has the default colormap and visual, which just so happens not to be the same as used by $window, the actual GdkWindow onto which you're rendering, so you get a BadMatch error. in this instance, the better thing to do would've been Gtk2::Gdk::GC->new ($window) instead.

3) but even the two solutions mentioned above aren't the right thing to do. GtkWidget keeps a pointer to a GtkStyle, which has a bunch of GdkGCs in it, already configured for the current mode! you should be using those!

so, the fix is:

        if ($pix_width > 1) {
                $window->draw_pixbuf(
- Gtk2::Gdk::GC->new(Gtk2::Gdk::Pixmap- >new(undef,$pix_width,$pix_height,8)),
+                               $widget->get_style->fg_gc ($widget->state),
                                $cell->get("pixbuf"),
                                0,
                                0,


so, now that that's out of the way... ;-)


Nevertheless, there are still two points I could need help with:

1. The GET_SIZE sub: This seems to get called, before the actual renderer has been executed. But before I render my column I do not know it's size - especially since the properties of the cell do not seem to be available yet.

sure they are; the column sets up the properties before calling get_size(). the cell_area always seems to be undef. i have seen it defined in the past but i don't remember the circumstances.

what you'll probably want to do is break the text handling out into a separate function, so you can find the size for yourself the same way you do in the RENDER method.



2. The text layout: I store my text in a Gtk2::Pango::Layout, is it possible to get it's height? I need this for the vertical centering of my text in the cell.

perldoc Gtk2::Pango::Layout lists

   (width, height) = $layout->get_pixel_size

(available since Gtk2 0.20)



here are my changes, incorporating most of what i mentioned above:

--- cellrenderer.pl     2004-04-29 20:14:13.000000000 -0400
+++ cellrenderer-mup.pl 2004-04-29 20:02:03.000000000 -0400
@@ -35,32 +35,43 @@

 sub MAX { $_[0] > $_[1] ? $_[0] : $_[1] }

+sub setup_text {
+       my ($self, $widget) = @_;
+       my $font = Gtk2::Pango::FontDescription->from_string
+                                               ($self->{font_string});
+       $font->set_weight ('bold')
+               if $self->{'weight_set'};
+       my $layout = $widget->create_pango_layout ($self->{'text'});
+       $layout->set_font_description ($font);
+
+       return ($layout->get_pixel_size, $layout);
+}
+
 sub GET_SIZE {
        my ($cell, $widget, $cell_area) = @_;
        my ($x_offset, $y_offset) = (0, 0);
-       
-       my $width  = 100;
-       my $height = 25;
-       
-#      if ($cell_area) {
-#              $x_offset = $cell->get ('xalign') * ($cell_area->width - $width);
-#              $x_offset = MAX ($x_offset, 0);
-#              
-#              $y_offset = $cell->get ('yalign') * ($cell_area->height - $height);
-#              $y_offset = MAX ($y_offset, 0);
-#      }
+
+       my ($width, $height) = $cell->setup_text ($widget);
+
+       if ($cell->{pixbuf}) {
+               my $pw = $cell->{pixbuf}->get_width;
+               my $ph = $cell->{pixbuf}->get_height;
+               $width += $pw;
+               $height = $ph
+                       if $ph > $height;
+       }
        
        return ($x_offset, $y_offset, $width, $height);
 }

 sub RENDER {
my ($cell, $window, $widget, $background_area, $cell_area, $expose_area, $flags) = @_;
-       my $pix_width  = $cell->get('pixbuf')->get_width;
-       my $pix_height = $cell->get('pixbuf')->get_height;
+       my $pix_width  = $cell->{pixbuf}->get_width;
+       my $pix_height = $cell->{pixbuf}->get_height;

        if ($pix_width > 1) {
                $window->draw_pixbuf(
- Gtk2::Gdk::GC->new(Gtk2::Gdk::Pixmap- >new(undef,$pix_width,$pix_height,8)),
+                               $widget->get_style->fg_gc($widget->state),
                                $cell->get("pixbuf"),
                                0,
                                0,
@@ -76,13 +87,7 @@
                $pix_width=0;
        }

- my $font = Gtk2::Pango::FontDescription->from_string($cell->get("font-string"));
-       if ($cell->{'weight_set'}) {
-               $font->set_weight('PANGO_WEIGHT_BOLD');
-       }
-       my $layout = $widget->create_pango_layout("");
-       $layout->set_text($cell->{'text'});
-       $layout->set_font_description($font);
+       my ($width, $height, $layout) = $cell->setup_text ($widget);

        $widget->get_style->paint_layout($window,
                        "normal",
@@ -90,8 +95,8 @@
                        $cell_area,
                        $widget,
                        "cellrenderertext",
-                       $cell_area->x() + $pix_width + 1,
-                       $cell_area->y(),
+                       $cell_area->x + $pix_width + 1,
+                       $cell_area->y + ($cell_area->height - $height) / 2,
                        $layout
        );
 }



--
"the ternary operator makes it a bit less ugly."
    -- kaffee




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]