0
votes

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!

2

2 Answers

0
votes

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;
}
0
votes

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;
}