How to manually draw the GtkTreeView expander - gtk

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!

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

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

Related

Alternative to deprecated gtk_alignment_new

I used the GtkAlignment widget to control the alignment and size of its child widget. But gtk_alignment_new has been deprecated since version 3.14 and should not be used in newly-written code. What functions should I use as alternatives to let the code be gtk3+ compatible?
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *halign;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Tooltip");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
gtk_container_set_border_width(GTK_CONTAINER(window), 15);
button = gtk_button_new_with_label("Button");
gtk_widget_set_tooltip_text(button, "Button widget");
halign = gtk_alignment_new(0, 0, 0, 0);
gtk_container_add(GTK_CONTAINER(halign), button);
gtk_container_add(GTK_CONTAINER(window), halign);
gtk_widget_show_all(window);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return 0;
}
As suggested in the comment, use these two functions instead:
void gtk_widget_set_halign (GtkWidget *widget, GtkAlign align);
Sets the horizontal alignment of widget.
gtk_widget_get_valign (GtkWidget *widget); Sets the vertical alignment of widget.
The enum GtkAlign types are the following:
GTK_ALIGN_START: The 'start' of the layout. Vertically this is the top, horizontally this is left/right according to LTR/RTL
GTK_ALIGN_END: Opposite of GTK_ALIGN_START
GTK_ALIGN_CENTER: The middle of the layout
GTK_ALIGN_FILL : Take all available space
for scaling use GTK_ALIGN_FILL.
So the gtk3+ compatible alternative for your code is the following:
#include <gtk/gtk.h>
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *button;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Tooltip");
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
gtk_container_set_border_width(GTK_CONTAINER(window), 15);
button = gtk_button_new_with_label("Button");
gtk_widget_set_tooltip_text(button, "Button widget");
gtk_widget_set_halign (button, GTK_ALIGN_START);
gtk_widget_set_valign (button, GTK_ALIGN_START);
gtk_container_add (GTK_CONTAINER (window), button);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}

GtkDrawingArea using Cairo doesn't apply in Windows 7

I work with GTK+ 2.24 in Windows 7 64-bit and Fedora 21 64-bit. I painted a drawing area to white, using Cairo. It works in Fedora, but not in Windows. Does anyone know the reason?
Here is my code:
static gboolean draw_background_cb(GtkWidget *widget _U_, cairo_t *cr, gpointer data _U_)
{
/* Set background color */
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_rectangle(cr, 0, 0, 300, 300);
cairo_paint(cr);
return FALSE;
}
int main(int argc, char *argv[])
{
GtkWidget *window;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "draw", G_CALLBACK (draw_background), NULL);
gtk_widget_show(window);
gtk_main();
return 0;
}
GTK+ 2 uses expose-event instead of draw for drawing. I don't know what the other differences are; sorry.

How to make a GTK3+ window with a background image

The Pixbuf method doesn't work anymore for GTK3+ because obsoleted/removed. I want to put a background image in the back of a GtkFixed, on the gdk part of the GtkWindow or a GtkBox. I believe I need Cairo graphics library to do this.
Can a pleasant soul guide me in the right direction?
I have hacked an example together. It fills the background of the toplevel application window with an image.
As background image i choosed a little star (1). To compile the example invoke gcc like
gcc `pkg-config --libs --cflags glib-2.0 gtk+-3.0` <source> -o <executable>
On my machine the result looks like
1 : http://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Featured_Star_green.svg/32px-Featured_Star_green.svg.png
#include <gtk/gtk.h>
#include <glib-2.0/glib.h>
typedef struct Texture_
{
gint root_width, root_height;
cairo_surface_t *bg_image;
} Texture;
typedef struct Ui_
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button;
Texture *texture;
gulong window_draw_cb_handler_id;
} Ui;
gboolean window_draw_cb (GtkWidget *, cairo_t *, Ui *);
void
button_clicked_cb (GtkWidget * widget, Ui * ui)
{
gboolean ret;
ret =
g_signal_handler_is_connected (ui->window,
ui->window_draw_cb_handler_id);
if (ret) {
g_signal_handler_disconnect (ui->window, ui->window_draw_cb_handler_id);
}
else {
ui->window_draw_cb_handler_id =
g_signal_connect (ui->window, "draw", G_CALLBACK (window_draw_cb),
ui);
}
gtk_widget_queue_draw (ui->window);
}
void
destroy_cb (GtkWidget * widget, gpointer data)
{
gtk_main_quit ();
}
gboolean
window_draw_cb (GtkWidget * widget, cairo_t * cr, Ui * ui)
{
cairo_set_source_surface (cr, ui->texture->bg_image, 0, 0);
cairo_rectangle (cr, 0, 0,
ui->texture->root_width, ui->texture->root_height);
cairo_fill (cr);
/* draw all widgets attached to `grid` to the
* cairo context of the mainwindow */
gtk_widget_draw (ui->grid, cr);
cairo_fill (cr);
return TRUE;
}
void
ui_texture_init (Ui * ui)
{
gint root_width, root_height, width, height;
guint n_x, n_y, i, k;
cairo_format_t format;
cairo_surface_t *bg_image, *target;
cairo_status_t ret;
GdkWindow *root;
cairo_t *cr;
ui->texture = g_new (Texture, 1);
bg_image =
cairo_image_surface_create_from_png ("./Featured_Star_green.svg.png");
ret = cairo_surface_status (bg_image);
g_assert (ret == 0);
format = cairo_image_surface_get_format (bg_image);
width = cairo_image_surface_get_width (bg_image);
height = cairo_image_surface_get_height (bg_image);
root = gdk_get_default_root_window ();
gdk_window_get_geometry (root, NULL, NULL, &root_width, &root_height);
target = cairo_image_surface_create (format, root_width, root_height);
cr = cairo_create (target);
n_x = root_width / width;
n_y = root_height / height;
for (i = 0; i <= n_x; i++) {
for (k = 0; k <= n_y; k++) {
cairo_set_source_surface (cr, bg_image, i * width, k * height);
cairo_rectangle (cr, i * width, k * height, width, height);
cairo_fill (cr);
}
}
ui->texture->root_width = root_width;
ui->texture->root_height = root_height;
ui->texture->bg_image = target;
}
void
forall_container (GtkWidget * widget, gpointer data)
{
gtk_widget_set_halign (widget, GTK_ALIGN_CENTER);
gtk_widget_set_valign (widget, GTK_ALIGN_CENTER);
gtk_widget_set_margin_top (widget, 10);
gtk_widget_set_margin_bottom (widget, 10);
gtk_widget_set_margin_left (widget, 10);
gtk_widget_set_margin_right (widget, 10);
}
Ui *
ui_init ()
{
Ui *ui;
GtkWidget *label, *entry;
PangoAttrList *attributes;
ui = g_new (Ui, 1);
ui_texture_init (ui);
ui->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
ui->grid = gtk_grid_new ();
gtk_grid_set_column_homogeneous (GTK_GRID (ui->grid), TRUE);
gtk_grid_set_row_homogeneous (GTK_GRID (ui->grid), TRUE);
gtk_grid_set_row_spacing (GTK_GRID (ui->grid), 10);
label = gtk_label_new ("Label:");
attributes = pango_attr_list_new ();
pango_attr_list_insert (attributes, pango_attr_size_new_absolute (30000));
gtk_label_set_attributes (GTK_LABEL (label), attributes);
entry = gtk_entry_new ();
ui->button = gtk_button_new_with_label ("Toggle background image");
gtk_grid_attach (GTK_GRID (ui->grid), label, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (ui->grid), entry, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (ui->grid), ui->button, 0, 1, 2, 1);
gtk_container_foreach (GTK_CONTAINER (ui->grid), &forall_container, NULL);
gtk_container_add (GTK_CONTAINER (ui->window), ui->grid);
return ui;
}
int
main (int argc, char *argv[])
{
Ui *ui;
gtk_init (&argc, &argv);
ui = ui_init ();
g_signal_connect (ui->window, "destroy", G_CALLBACK (destroy_cb), ui);
ui->window_draw_cb_handler_id =
g_signal_connect (ui->window, "draw", G_CALLBACK (window_draw_cb), ui);
g_signal_connect (ui->button, "clicked", G_CALLBACK (button_clicked_cb),
ui);
gtk_widget_show_all (ui->window);
gtk_main ();
}

adding image widget on gtklayout

I have put an image on gtklayout calling put method, but i could not get the image visible.
What is the procedure for putting an image gtklayout object so that it appears as its back ground.
Regards,
iSight
pls check if the code below would work for you:
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *layout;
GtkWidget *image;
GtkWidget *button;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 290, 200);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
layout = gtk_layout_new(NULL, NULL);
gtk_container_add(GTK_CONTAINER (window), layout);
gtk_widget_show(layout);
image = gtk_image_new_from_file("/home/my_test_image.jpg"); // put path to your image here
gtk_layout_put(GTK_LAYOUT(layout), image, 0, 0);
button = gtk_button_new_with_label("Button");
gtk_layout_put(GTK_LAYOUT(layout), button, 150, 50);
gtk_widget_set_size_request(button, 80, 35);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
hope this helps, regards

opencv image update in gtk for video streaming linux with C programming

I am using opencv 1.0.0 and gtk2.0. I want to grab images continuously from a video stream. So far I have successfully been able to grab still image. This is non standard IP camera not VGA/USB /V4L one so need to know explicit method to refresh or update images continuously for video streaming!
GtkWidget *image;
...
...
IplImage* bayerImage = NULL;
IplImage* rgbImage = NULL;
...
...
...
cvCvtColor( bayerImage, rgbImage, CV_BayerBG2RGB );
// Usually opencv image is BGR, so we need to change it to RGB
pix = gdk_pixbuf_new_from_data ((guchar*)rgbImage->imageData,
GDK_COLORSPACE_RGB,
FALSE,
rgbImage->depth,
rgbImage->width,
rgbImage->height,
(rgbImage->widthStep),
NULL,
NULL);
image = gtk_image_new_from_pixbuf (pix);
/* (c) 2010 Virgoptrex. Feel Free to use. Leave credits intact */
#include gtk/gtk.h
gint t=0;
gboolean
expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
//g_object_ref_sink (widget->window);
// gdk_drawable_ref (widget->window);
gdk_draw_arc (widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
TRUE,
0, 0, widget->allocation.width, widget->allocation.height,
0, 64 * 18*t);
//gdk_drawable_unref (widget->window);
return TRUE;
}
static gboolean
time_handler(GtkWidget *widget)
{
gtk_widget_queue_draw(GTK_WIDGET(widget));
if (t<20)
{ t++; }
else if (t >=20)
{ t=0; }
printf("hello %d\n",t);
return TRUE;
}
int main( int argc,
char *argv[] )
{
GtkWidget *window;
GtkWidget *aspect_frame;
GtkWidget *drawing_area;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* Create an aspect_frame and add it to our toplevel window */
aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
0.5, /* center x */
0.5, /* center y */
2, /* xsize/ysize = 2 */
FALSE /* ignore child's aspect */);
gtk_container_add (GTK_CONTAINER (window), aspect_frame);
gtk_widget_show (aspect_frame);
/* Now add a child widget to the aspect frame */
drawing_area = gtk_drawing_area_new ();
/* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
* window since we are forcing a 2x1 aspect ratio */
gtk_widget_set_size_request (drawing_area, 200, 200);
gtk_container_add (GTK_CONTAINER (aspect_frame), drawing_area);
gtk_widget_show (drawing_area);
g_signal_connect (G_OBJECT (drawing_area), "expose_event",
G_CALLBACK (expose_event_callback), NULL);
g_timeout_add(100, (GSourceFunc) time_handler, (gpointer)drawing_area);
gtk_widget_show (window);
gtk_main ();
return 0;
}