Merged pidgin/main into default
[pidgin-git.git] / pidgin / gtkcellrendererexpander.c
blob316c430bd84c2660696c75edb6db2afec970843c
1 /* pidgin
3 * Pidgin is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 /* This is taken largely from GtkCellRenderer[Text|Pixbuf|Toggle] by
24 * Jonathon Blandford <jrb@redhat.com> for RedHat, Inc.
27 #include "gtkcellrendererexpander.h"
29 #include "gtk3compat.h"
31 static void pidgin_cell_renderer_expander_get_property (GObject *object,
32 guint param_id,
33 GValue *value,
34 GParamSpec *pspec);
35 static void pidgin_cell_renderer_expander_set_property (GObject *object,
36 guint param_id,
37 const GValue *value,
38 GParamSpec *pspec);
39 static void pidgin_cell_renderer_expander_init (PidginCellRendererExpander *cellexpander);
40 static void pidgin_cell_renderer_expander_class_init (PidginCellRendererExpanderClass *class);
41 static void pidgin_cell_renderer_expander_get_size (GtkCellRenderer *cell,
42 GtkWidget *widget,
43 const GdkRectangle *cell_area,
44 gint *x_offset,
45 gint *y_offset,
46 gint *width,
47 gint *height);
48 static void pidgin_cell_renderer_expander_render (GtkCellRenderer *cell,
49 cairo_t *cr,
50 GtkWidget *widget,
51 const GdkRectangle *background_area,
52 const GdkRectangle *cell_area,
53 GtkCellRendererState flags);
54 static gboolean pidgin_cell_renderer_expander_activate (GtkCellRenderer *r,
55 GdkEvent *event,
56 GtkWidget *widget,
57 const gchar *p,
58 const GdkRectangle *bg,
59 const GdkRectangle *cell,
60 GtkCellRendererState flags);
61 static void pidgin_cell_renderer_expander_finalize (GObject *gobject);
63 enum {
64 LAST_SIGNAL
67 enum {
68 PROP_0,
69 PROP_IS_EXPANDER
72 static gpointer parent_class;
73 /* static guint expander_cell_renderer_signals [LAST_SIGNAL]; */
75 GType pidgin_cell_renderer_expander_get_type (void)
77 static GType cell_expander_type = 0;
79 if (!cell_expander_type)
81 static const GTypeInfo cell_expander_info =
83 sizeof (PidginCellRendererExpanderClass),
84 NULL, /* base_init */
85 NULL, /* base_finalize */
86 (GClassInitFunc) pidgin_cell_renderer_expander_class_init,
87 NULL, /* class_finalize */
88 NULL, /* class_data */
89 sizeof (PidginCellRendererExpander),
90 0, /* n_preallocs */
91 (GInstanceInitFunc) pidgin_cell_renderer_expander_init,
92 NULL /* value_table */
95 cell_expander_type =
96 g_type_register_static (GTK_TYPE_CELL_RENDERER,
97 "PidginCellRendererExpander",
98 &cell_expander_info, 0);
101 return cell_expander_type;
104 static void pidgin_cell_renderer_expander_init (PidginCellRendererExpander *cellexpander)
106 g_object_set(G_OBJECT(cellexpander), "mode",
107 GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
108 gtk_cell_renderer_set_padding(GTK_CELL_RENDERER(cellexpander), 0, 2);
111 static void pidgin_cell_renderer_expander_class_init (PidginCellRendererExpanderClass *class)
113 GObjectClass *object_class = G_OBJECT_CLASS(class);
114 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(class);
116 parent_class = g_type_class_peek_parent (class);
117 object_class->finalize = pidgin_cell_renderer_expander_finalize;
119 object_class->get_property = pidgin_cell_renderer_expander_get_property;
120 object_class->set_property = pidgin_cell_renderer_expander_set_property;
122 cell_class->get_size = pidgin_cell_renderer_expander_get_size;
123 cell_class->render = pidgin_cell_renderer_expander_render;
124 cell_class->activate = pidgin_cell_renderer_expander_activate;
126 g_object_class_install_property (object_class,
127 PROP_IS_EXPANDER,
128 g_param_spec_boolean ("expander-visible",
129 "Is Expander",
130 "True if the renderer should draw an expander",
131 FALSE,
132 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
135 static void pidgin_cell_renderer_expander_finalize (GObject *object)
138 PidginCellRendererExpander *cellexpander = PIDGIN_CELL_RENDERER_EXPANDER(object);
141 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
144 static void pidgin_cell_renderer_expander_get_property (GObject *object,
145 guint param_id,
146 GValue *value,
147 GParamSpec *psec)
149 PidginCellRendererExpander *cellexpander = PIDGIN_CELL_RENDERER_EXPANDER(object);
151 switch (param_id)
153 case PROP_IS_EXPANDER:
154 g_value_set_boolean(value, cellexpander->is_expander);
155 break;
156 default:
157 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec);
158 break;
163 static void pidgin_cell_renderer_expander_set_property (GObject *object,
164 guint param_id,
165 const GValue *value,
166 GParamSpec *pspec)
168 PidginCellRendererExpander *cellexpander = PIDGIN_CELL_RENDERER_EXPANDER (object);
170 switch (param_id)
172 case PROP_IS_EXPANDER:
173 cellexpander->is_expander = g_value_get_boolean(value);
174 break;
175 default:
176 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
177 break;
181 GtkCellRenderer *pidgin_cell_renderer_expander_new(void)
183 return g_object_new(PIDGIN_TYPE_CELL_RENDERER_EXPANDER, NULL);
186 static void
187 pidgin_cell_renderer_expander_get_size (GtkCellRenderer *cell,
188 GtkWidget *widget,
189 const GdkRectangle *cell_area,
190 gint *x_offset,
191 gint *y_offset,
192 gint *width,
193 gint *height)
195 gint calc_width;
196 gint calc_height;
197 gint expander_size;
198 gint xpad;
199 gint ypad;
200 gfloat xalign;
201 gfloat yalign;
203 gtk_widget_style_get(widget, "expander-size", &expander_size, NULL);
205 gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
206 gtk_cell_renderer_get_alignment(cell, &xalign, &yalign);
207 calc_width = (gint) xpad * 2 + expander_size;
208 calc_height = (gint) ypad * 2 + expander_size;
210 if (width)
211 *width = calc_width;
213 if (height)
214 *height = calc_height;
216 if (cell_area)
218 if (x_offset)
220 *x_offset = xalign * (cell_area->width - calc_width);
221 *x_offset = MAX (*x_offset, 0);
223 if (y_offset)
225 *y_offset = yalign * (cell_area->height - calc_height);
226 *y_offset = MAX (*y_offset, 0);
232 static void
233 pidgin_cell_renderer_expander_render(GtkCellRenderer *cell,
234 cairo_t *cr,
235 GtkWidget *widget,
236 const GdkRectangle *background_area,
237 const GdkRectangle *cell_area,
238 GtkCellRendererState flags)
240 PidginCellRendererExpander *cellexpander = (PidginCellRendererExpander *) cell;
241 gboolean set;
242 gint width, height;
243 GtkStateFlags state;
244 gint xpad;
245 gint ypad;
246 gboolean is_expanded;
247 GtkAllocation allocation;
248 GtkStyleContext *context;
250 if (!cellexpander->is_expander)
251 return;
253 gtk_cell_renderer_get_padding(cell, &xpad, &ypad);
254 g_object_get(G_OBJECT(cell), "is-expanded", &is_expanded, NULL);
256 width = cell_area->width;
257 height = cell_area->height;
259 if (!gtk_widget_get_sensitive(widget))
260 state = GTK_STATE_FLAG_INSENSITIVE;
261 else if (flags & GTK_CELL_RENDERER_PRELIT)
262 state = GTK_STATE_FLAG_PRELIGHT;
263 else if (gtk_widget_has_focus(widget) && flags & GTK_CELL_RENDERER_SELECTED)
264 state = GTK_STATE_FLAG_ACTIVE;
265 else
266 state = GTK_STATE_FLAG_NORMAL;
268 width -= xpad*2;
269 height -= ypad*2;
271 #if GTK_CHECK_VERSION(3,14,0)
272 if (is_expanded)
273 state |= GTK_STATE_FLAG_CHECKED;
274 else
275 state &= ~GTK_STATE_FLAG_CHECKED;
276 #else
277 if (is_expanded)
278 state |= GTK_STATE_FLAG_ACTIVE;
279 else
280 state &= ~GTK_STATE_FLAG_ACTIVE;
281 #endif
283 context = gtk_widget_get_style_context(widget);
284 gtk_style_context_add_class(context, GTK_STYLE_CLASS_VIEW);
285 gtk_style_context_add_class(context, GTK_STYLE_CLASS_EXPANDER);
286 gtk_style_context_set_state(context, state);
287 gtk_render_expander(context, cr,
288 cell_area->x + xpad, cell_area->y + ypad,
289 width, height);
291 /* only draw the line if the color isn't set - this prevents a bug where the hline appears only under the expander */
292 g_object_get(cellexpander, "cell-background-set", &set, NULL);
293 gtk_widget_get_allocation(widget, &allocation);
295 if (is_expanded && !set)
296 gtk_render_line(context, cr, 0, cell_area->y + cell_area->height,
297 allocation.width, cell_area->y + cell_area->height);
300 static gboolean
301 pidgin_cell_renderer_expander_activate(GtkCellRenderer *r,
302 GdkEvent *event,
303 GtkWidget *widget,
304 const gchar *p,
305 const GdkRectangle *bg,
306 const GdkRectangle *cell,
307 GtkCellRendererState flags)
309 GtkTreePath *path = gtk_tree_path_new_from_string(p);
310 if (gtk_tree_view_row_expanded(GTK_TREE_VIEW(widget), path))
311 gtk_tree_view_collapse_row(GTK_TREE_VIEW(widget), path);
312 else
313 gtk_tree_view_expand_row(GTK_TREE_VIEW(widget),path,FALSE);
314 gtk_tree_path_free(path);
315 return FALSE;