0

I'm using a GtkTreeView widget and I want to change the appearance of the "expander" icon that opens and closes child rows: I want the icons to be the triangels that we're all familiar with, but they're appearing as boxed "+" and "-" symbols instead.

At first I thought there must be a style enumeration that I can set, but I cannot find one. Then, I thought maybe there's a style property I can set in my theme's gtkrc file, but I don't think there is one. Finally, I resorted to trying to manually override the draw method like so:

GtkWidget *pTreeView = gtk_tree_view_new_with_model((GtkTreeModel *)pTreeModel);
(GTK_STYLE_GET_CLASS(pTreeView->style))->draw_expander = my_draw_expander_override;

But my_draw_expander_override() never gets called and the expanders are still the boxed "+" and "-" icons.

Does anyone know how can I change the appearance of the GtkTreeView expander icons or just draw them myself?

Thanks a bunch in advance!

Andreas
  • 5,393
  • 9
  • 44
  • 53
user2062604
  • 247
  • 3
  • 16

2 Answers2

0

Here the sample code of how to overwrite draw_expander. You'll definetely have to take a look in the manual to get all the parameters right.

#include <gtk/gtk.h>
#include <cairo.h>


enum {
  COL_1,
  N_COLS
};

void draw_expander (GtkStyle        *style,
                    GdkWindow       *window,
                    GtkStateType         state_type,
                    GdkRectangle    *area,
                    GtkWidget       *widget,
                    const gchar     *detail,
                    gint         x,
                    gint         y,
                    GtkExpanderStyle     expander_style) {


  cairo_t *cr;

  cr = gdk_cairo_create (window);

  cairo_set_source_rgb(cr, 0, 0, 0);

  cairo_move_to (cr, 0, 0);
  cairo_line_to (cr, 0, 10);
  cairo_line_to (cr, 10, 5);
  cairo_close_path (cr);

  cairo_stroke  (cr);
}


GtkWidget *build_view (); /* just supply your own */


int main (int argc, char *argv[]) {
  gtk_init (&argc, &argv);

  GtkWidget *window;
  GtkWidget *view;

  window = g_object_new (GTK_TYPE_WINDOW, NULL);  
  view = build_view ();
  gtk_container_add (GTK_CONTAINER (window), view);

  GtkStyle *style = gtk_widget_get_style (view);
  GtkStyleClass *klass = GTK_STYLE_GET_CLASS (style);

  klass->draw_expander = draw_expander;

  gtk_widget_show_all (window);
  gtk_main ();

  return 0;
}
mikyra
  • 10,077
  • 1
  • 40
  • 41
  • Thanks for all your help. Interestingly enough, your solution is pretty much identical what I proposed in my question, but something about the timing of when I set the draw_expander function made all the difference - I moved the (GTK_STYLE_GET_CLASS(pTreeView->style))->draw_expander = my_draw_expander call to after all of my widget modifications and it worked! Thanks again, great job. – user2062604 Feb 12 '13 at 14:23
0

Maybe you should just try to switch to a theme that draws expanders the way you want them to be displayed, as I am quite sure some of your users might find it a little rude if you "force" them to approve that triangles are the one and only way to draw expanders and deny them any chance to change this.

That's especially what themes were made for - such that everybody can have the look she wants.

Well, anyway unfortunately actually GTK is in a transition from version 2 to version 3, so depending on the version you are using you would have to overwrite another signal.

It should be a little bit easier in GTK 3 since you already get your cairo context in the "draw" signal, but it's also possible in GTK 2, here you would have to use the "expose-event" signal.

Here as an example here a snippet of how to do it with GTK version 2. As I am no real artist it might not look too nice, but I'm sure you will come up with a nice design.

... ah, and don't forget to change the way it's painted depedning on its state ...

#include <gtk/gtk.h>
#include <cairo.h>


gboolean draw (GtkWidget *widget, GdkEventExpose *event, gpointer data) {

  cairo_t *cr;

  cr = gdk_cairo_create (widget->window);

  cairo_set_source_rgb(cr, 0, 0, 0);

  cairo_move_to (cr, 0, 0);
  cairo_line_to (cr, 0, 10);
  cairo_line_to (cr, 10, 5);
  cairo_close_path (cr);

  cairo_stroke  (cr);

  return TRUE;
}


int main (int argc, char *argv[]) {
  gtk_init (&argc, &argv);

  GtkWidget *window;
  GtkWidget *expander;


  window = g_object_new (GTK_TYPE_WINDOW, NULL);  
  expander = g_object_new (GTK_TYPE_EXPANDER, NULL);
  gtk_container_add (GTK_CONTAINER (window), expander);

  g_signal_connect (expander, "expose-event", draw, NULL);

  gtk_widget_show_all (window);
  gtk_main ();

  return 0;
}

EDIT:

As I saw you don't seem to want to change the appearance for just one instance, but for ALL expanders. To accomplish this you would have to overwrite the default handler like this:

#include <gtk/gtk.h>
#include <cairo.h>


gboolean draw (GtkWidget *widget, GdkEventExpose *event) {

  cairo_t *cr;

  cr = gdk_cairo_create (widget->window);

  cairo_set_source_rgb(cr, 0, 0, 0);

  cairo_move_to (cr, 0, 0);
  cairo_line_to (cr, 0, 10);
  cairo_line_to (cr, 10, 5);
  cairo_close_path (cr);

  cairo_stroke  (cr);

  return TRUE;
}


int main (int argc, char *argv[]) {
  gtk_init (&argc, &argv);

  GtkWidget *window;
  GtkWidget *expander;
  GtkWidgetClass *klass;

  window = g_object_new (GTK_TYPE_WINDOW, NULL);  
  expander = g_object_new (GTK_TYPE_EXPANDER, NULL);
  gtk_container_add (GTK_CONTAINER (window), expander);

  klass = g_type_class_peek (GTK_TYPE_EXPANDER);
  klass->expose_event =  draw;

  gtk_widget_show_all (window);
  gtk_main ();

  return 0;
}
mikyra
  • 10,077
  • 1
  • 40
  • 41
  • Thanks a bunch for your response! Unfortunately I do not understand how to connect to the expander's draw signal because I can't isolate the expander widget from the GtkTreeView widget. I have an existing GtkTreeView widget and I need to change the appearance of the expanders that it uses. Do you know how to do that? – user2062604 Feb 11 '13 at 22:16
  • I'm not sure how this is handled in GTK 3 as the old styling system seems to be marked deprecated, but with GTK 2 you would have to go for the Style associated with your view and overwrite the draw_expander method. – mikyra Feb 12 '13 at 00:35
  • Just take a look at the example above how to perform this – mikyra Feb 12 '13 at 00:49