libyui-gtk-pkg  2.42.9
 All Classes
ygtkcellrenderersidebutton.c
1 /********************************************************************
2  * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
3  ********************************************************************/
4 
5 /* YGtkCellRendererSideButton widget */
6 // check the header file for information about this widget
7 
8 #include "ygtkcellrenderersidebutton.h"
9 #include <gtk/gtk.h>
10 
11 enum {
12  PROP_0,
13  PROP_ACTIVE,
14  PROP_STOCK_ID,
15  PROP_BUTTON_VISIBLE,
16 };
17 
18 static guint toggle_cell_signal = 0;
19 
20 G_DEFINE_TYPE (YGtkCellRendererSideButton, ygtk_cell_renderer_side_button, GTK_TYPE_CELL_RENDERER_TEXT)
21 
22 #define DEPRESS_PAD 1
23 
24 static void ygtk_cell_renderer_side_button_init (YGtkCellRendererSideButton *bcell)
25 { g_object_set(GTK_CELL_RENDERER(bcell), "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL); }
26 
27 static void free_pixbuf (YGtkCellRendererSideButton *cell)
28 {
29  if (cell->stock_id) {
30  g_free (cell->stock_id);
31  cell->stock_id = NULL;
32  }
33  if (cell->pixbuf) {
34  g_object_unref (cell->pixbuf);
35  cell->pixbuf = NULL;
36  }
37 }
38 
39 static void ensure_pixbuf (YGtkCellRendererSideButton *cell, GtkWidget *widget)
40 {
41  if (!cell->pixbuf && cell->stock_id)
42  cell->pixbuf = gtk_widget_render_icon (widget, cell->stock_id, GTK_ICON_SIZE_BUTTON, NULL);
43 }
44 
45 static void ygtk_cell_renderer_side_button_finalize (GObject *object)
46 {
47  YGtkCellRendererSideButton *bcell = YGTK_CELL_RENDERER_SIDE_BUTTON (object);
48  free_pixbuf (bcell);
49  G_OBJECT_CLASS (ygtk_cell_renderer_side_button_parent_class)->finalize (object);
50 }
51 
52 static void ygtk_cell_renderer_side_button_get_property (
53  GObject *object, guint param_id, GValue *value, GParamSpec *pspec)
54 {
55  if (pspec->owner_type == YGTK_TYPE_CELL_RENDERER_SIDE_BUTTON) {
56  YGtkCellRendererSideButton *bcell = YGTK_CELL_RENDERER_SIDE_BUTTON (object);
57  switch (param_id) {
58  case PROP_ACTIVE:
59  g_value_set_boolean (value, bcell->active);
60  break;
61  case PROP_STOCK_ID:
62  g_value_set_string (value, bcell->stock_id);
63  break;
64  case PROP_BUTTON_VISIBLE:
65  g_value_set_boolean (value, bcell->button_visible);
66  break;
67  }
68  }
69  else
70  G_OBJECT_CLASS (ygtk_cell_renderer_side_button_parent_class)->get_property (
71  object, param_id, value, pspec);
72 }
73 
74 static void ygtk_cell_renderer_side_button_set_property (GObject *object,
75  guint param_id, const GValue *value, GParamSpec *pspec)
76 {
77  if (pspec->owner_type == YGTK_TYPE_CELL_RENDERER_SIDE_BUTTON) {
78  YGtkCellRendererSideButton *bcell = YGTK_CELL_RENDERER_SIDE_BUTTON (object);
79  switch (param_id) {
80  case PROP_ACTIVE:
81  bcell->active = g_value_get_boolean (value);
82  break;
83  case PROP_STOCK_ID:
84  free_pixbuf (bcell);
85  bcell->stock_id = g_value_dup_string (value);
86  break;
87  case PROP_BUTTON_VISIBLE:
88  bcell->button_visible = g_value_get_boolean (value);
89  break;
90  }
91  }
92  else
93  G_OBJECT_CLASS (ygtk_cell_renderer_side_button_parent_class)->set_property (
94  object, param_id, value, pspec);
95 }
96 
97 static void ygtk_cell_renderer_side_button_get_size (
98  GtkCellRenderer *cell, GtkWidget *widget, const GdkRectangle *cell_area,
99  gint *x_offset, gint *y_offset, gint *width, gint *height)
100 {
101  GTK_CELL_RENDERER_CLASS (ygtk_cell_renderer_side_button_parent_class)->get_size (
102  cell, widget, cell_area, x_offset, y_offset, width, height);
103  YGtkCellRendererSideButton *bcell = YGTK_CELL_RENDERER_SIDE_BUTTON (cell);
104  if (bcell->button_visible) {
105  gint icon_width, icon_height;
106  gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, &icon_width, &icon_height);
107  *width += icon_width + 8 + 4;
108  }
109 }
110 
111 static void ygtk_cell_renderer_side_button_render (
112  GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget,
113  const GdkRectangle *background_area, const GdkRectangle *cell_area,
114  GtkCellRendererState flags)
115 {
116  YGtkCellRendererSideButton *bcell = YGTK_CELL_RENDERER_SIDE_BUTTON (cell);
117  GdkRectangle text_area = *cell_area;
118  gint icon_width, icon_height;
119  if (bcell->button_visible) {
120  gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, &icon_width, &icon_height);
121  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
122  text_area.x += icon_width + 8;
123  text_area.width -= icon_width + 8 + 4;
124  }
125 
126  GTK_CELL_RENDERER_CLASS (ygtk_cell_renderer_side_button_parent_class)->render (
127  cell, cr, widget, background_area, &text_area, flags);
128 
129  if (bcell->button_visible) {
130  GtkStateType state = GTK_STATE_NORMAL;
131  gboolean sensitive = TRUE;
132  g_object_get(cell, "sensitive", &sensitive, NULL);
133  if (!sensitive || gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
134  state = GTK_STATE_INSENSITIVE;
135  /* else if ((flags & GTK_CELL_RENDERER_PRELIT))
136  state = GTK_STATE_PRELIGHT;*/
137  if (bcell->active)
138  state = GTK_STATE_ACTIVE;
139 
140  GtkStyleContext *style = gtk_widget_get_style_context(widget);
141  gtk_style_context_save(style);
142  gtk_style_context_set_state(style, state);
143  gtk_style_context_add_class (style, GTK_STYLE_CLASS_BUTTON);
144 
145  GdkRectangle button_area = *cell_area;
146  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
147  button_area.x = cell_area->x + 2;
148  else
149  button_area.x = cell_area->x + cell_area->width - icon_width - 8;
150  button_area.width = icon_width + 4;
151  button_area.height = icon_height + 4;
152  button_area.y = cell_area->y + ((cell_area->height - button_area.height) / 2);
153 
154  gtk_render_background (style, cr, button_area.x, button_area.y, button_area.width, button_area.height);
155  gtk_render_frame (style, cr, button_area.x, button_area.y, button_area.width, button_area.height);
156 
157  GdkRectangle icon_area = button_area;
158  icon_area.x += 2;
159  icon_area.y += 2;
160  if (bcell->active) {
161  icon_area.x += DEPRESS_PAD; icon_area.y += DEPRESS_PAD;
162  }
163 
164  ensure_pixbuf (bcell, widget);
165  gdk_cairo_set_source_pixbuf (cr, bcell->pixbuf, icon_area.x, icon_area.y);
166  cairo_rectangle (cr, icon_area.x, icon_area.y, icon_width, icon_height);
167  cairo_fill (cr);
168 
169  gtk_style_context_restore(style);
170  }
171 }
172 
173 static gboolean ygtk_cell_renderer_side_button_activate (
174  GtkCellRenderer *cell, GdkEvent *event, GtkWidget *widget, const gchar *path,
175  const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags)
176 {
177  YGtkCellRendererSideButton *bcell = YGTK_CELL_RENDERER_SIDE_BUTTON (cell);
178  if (bcell->button_visible) {
179  GdkEventButton *_event = (GdkEventButton *) event;
180  gint icon_width, icon_height;
181  gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, &icon_width, &icon_height);
182  int icon_x, x = _event->x - cell_area->x;
183  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
184  icon_x = 2;
185  else
186  icon_x = cell_area->width - (icon_width+12);
187  icon_width += 8;
188  if (x >= icon_x && x <= icon_x + icon_width) {
189  g_signal_emit (cell, toggle_cell_signal, 0, path);
190  return TRUE;
191  }
192  }
193  return FALSE;
194 }
195 
196 GtkCellRenderer *ygtk_cell_renderer_side_button_new (void)
197 { return g_object_new (YGTK_TYPE_CELL_RENDERER_SIDE_BUTTON, NULL); }
198 
199 gboolean ygtk_cell_renderer_side_button_get_active (YGtkCellRendererSideButton *cell)
200 { return cell->active; }
201 
202 static void ygtk_cell_renderer_side_button_class_init (YGtkCellRendererSideButtonClass *class)
203 {
204  GObjectClass *object_class = G_OBJECT_CLASS (class);
205  object_class->get_property = ygtk_cell_renderer_side_button_get_property;
206  object_class->set_property = ygtk_cell_renderer_side_button_set_property;
207  object_class->finalize = ygtk_cell_renderer_side_button_finalize;
208 
209  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
210  cell_class->get_size = ygtk_cell_renderer_side_button_get_size;
211  cell_class->render = ygtk_cell_renderer_side_button_render;
212  cell_class->activate = ygtk_cell_renderer_side_button_activate;
213 
214  GParamFlags readwrite_flag =
215  G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB;
216  g_object_class_install_property (object_class, PROP_ACTIVE,
217  g_param_spec_boolean ("active", "Toggle state", "The toggle state of the button",
218  FALSE, readwrite_flag));
219  g_object_class_install_property (object_class, PROP_STOCK_ID,
220  g_param_spec_string ("stock-id", "Stock ID", "Stock icon to render", NULL, readwrite_flag));
221  g_object_class_install_property (object_class, PROP_BUTTON_VISIBLE,
222  g_param_spec_boolean ("button-visible", "Is Button Visible", "Whether to show side button", TRUE, readwrite_flag));
223 
224  toggle_cell_signal = g_signal_new ("toggled", G_OBJECT_CLASS_TYPE (object_class),
225  G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (YGtkCellRendererSideButtonClass, toggled),
226  NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
227 }
228