]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-cell-renderer-expander.c
f7c8736172e957559d8c2ade29ebb359e573c258
[empathy.git] / libempathy-gtk / empathy-cell-renderer-expander.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2006-2007 Imendio AB
4  * Copyright (C) 2007-2011 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301  USA
20  *
21  * Authors: Kristian Rietveld <kris@imendio.com>
22  */
23
24 #include <libempathy/empathy-utils.h>
25 #include "empathy-cell-renderer-expander.h"
26
27 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCellRendererExpander)
28 typedef struct {
29         GtkExpanderStyle     expander_style;
30         gint                 expander_size;
31
32         guint                activatable : 1;
33 } EmpathyCellRendererExpanderPriv;
34
35 enum {
36         PROP_0,
37         PROP_EXPANDER_STYLE,
38         PROP_EXPANDER_SIZE,
39         PROP_ACTIVATABLE
40 };
41
42 static void     empathy_cell_renderer_expander_get_property (GObject                         *object,
43                                                             guint                            param_id,
44                                                             GValue                          *value,
45                                                             GParamSpec                      *pspec);
46 static void     empathy_cell_renderer_expander_set_property (GObject                         *object,
47                                                             guint                            param_id,
48                                                             const GValue                    *value,
49                                                             GParamSpec                      *pspec);
50 static void     empathy_cell_renderer_expander_finalize     (GObject                         *object);
51 static void     empathy_cell_renderer_expander_get_size     (GtkCellRenderer                 *cell,
52                                                             GtkWidget                       *widget,
53                                                             const GdkRectangle              *cell_area,
54                                                             gint                            *x_offset,
55                                                             gint                            *y_offset,
56                                                             gint                            *width,
57                                                             gint                            *height);
58 static void     empathy_cell_renderer_expander_render       (GtkCellRenderer                 *cell,
59                                                             cairo_t *cr,
60                                                             GtkWidget                       *widget,
61                                                             const GdkRectangle              *background_area,
62                                                             const GdkRectangle              *cell_area,
63                                                             GtkCellRendererState             flags);
64 static gboolean empathy_cell_renderer_expander_activate     (GtkCellRenderer                 *cell,
65                                                             GdkEvent                        *event,
66                                                             GtkWidget                       *widget,
67                                                             const gchar                     *path,
68                                                             const GdkRectangle              *background_area,
69                                                             const GdkRectangle              *cell_area,
70                                                             GtkCellRendererState             flags);
71
72 G_DEFINE_TYPE (EmpathyCellRendererExpander, empathy_cell_renderer_expander, GTK_TYPE_CELL_RENDERER)
73
74 static void
75 empathy_cell_renderer_expander_init (EmpathyCellRendererExpander *expander)
76 {
77         EmpathyCellRendererExpanderPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (expander,
78                 EMPATHY_TYPE_CELL_RENDERER_EXPANDER, EmpathyCellRendererExpanderPriv);
79
80         expander->priv = priv;
81         priv->expander_style = GTK_EXPANDER_COLLAPSED;
82         priv->expander_size = 12;
83         priv->activatable = TRUE;
84
85         g_object_set (expander,
86                       "xpad", 2,
87                       "ypad", 2,
88                       "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
89                       NULL);
90 }
91
92 static void
93 empathy_cell_renderer_expander_class_init (EmpathyCellRendererExpanderClass *klass)
94 {
95         GObjectClass         *object_class;
96         GtkCellRendererClass *cell_class;
97
98         object_class  = G_OBJECT_CLASS (klass);
99         cell_class = GTK_CELL_RENDERER_CLASS (klass);
100
101         object_class->finalize = empathy_cell_renderer_expander_finalize;
102
103         object_class->get_property = empathy_cell_renderer_expander_get_property;
104         object_class->set_property = empathy_cell_renderer_expander_set_property;
105
106         cell_class->get_size = empathy_cell_renderer_expander_get_size;
107         cell_class->render = empathy_cell_renderer_expander_render;
108         cell_class->activate = empathy_cell_renderer_expander_activate;
109
110         g_object_class_install_property (object_class,
111                                          PROP_EXPANDER_STYLE,
112                                          g_param_spec_enum ("expander-style",
113                                                             "Expander Style",
114                                                             "Style to use when painting the expander",
115                                                             GTK_TYPE_EXPANDER_STYLE,
116                                                             GTK_EXPANDER_COLLAPSED,
117                                                             G_PARAM_READWRITE));
118
119         g_object_class_install_property (object_class,
120                                          PROP_EXPANDER_SIZE,
121                                          g_param_spec_int ("expander-size",
122                                                            "Expander Size",
123                                                            "The size of the expander",
124                                                            0,
125                                                            G_MAXINT,
126                                                            12,
127                                                            G_PARAM_READWRITE));
128
129         g_object_class_install_property (object_class,
130                                          PROP_ACTIVATABLE,
131                                          g_param_spec_boolean ("activatable",
132                                                                "Activatable",
133                                                                "The expander can be activated",
134                                                                TRUE,
135                                                                G_PARAM_READWRITE));
136
137         g_type_class_add_private (object_class, sizeof (EmpathyCellRendererExpanderPriv));
138 }
139
140 static void
141 empathy_cell_renderer_expander_get_property (GObject    *object,
142                                             guint       param_id,
143                                             GValue     *value,
144                                             GParamSpec *pspec)
145 {
146         EmpathyCellRendererExpander     *expander;
147         EmpathyCellRendererExpanderPriv *priv;
148
149         expander = EMPATHY_CELL_RENDERER_EXPANDER (object);
150         priv = GET_PRIV (expander);
151
152         switch (param_id) {
153         case PROP_EXPANDER_STYLE:
154                 g_value_set_enum (value, priv->expander_style);
155                 break;
156
157         case PROP_EXPANDER_SIZE:
158                 g_value_set_int (value, priv->expander_size);
159                 break;
160
161         case PROP_ACTIVATABLE:
162                 g_value_set_boolean (value, priv->activatable);
163                 break;
164
165         default:
166                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
167                 break;
168         }
169 }
170
171 static void
172 empathy_cell_renderer_expander_set_property (GObject      *object,
173                                             guint         param_id,
174                                             const GValue *value,
175                                             GParamSpec   *pspec)
176 {
177         EmpathyCellRendererExpander     *expander;
178         EmpathyCellRendererExpanderPriv *priv;
179
180         expander = EMPATHY_CELL_RENDERER_EXPANDER (object);
181         priv = GET_PRIV (expander);
182
183         switch (param_id) {
184         case PROP_EXPANDER_STYLE:
185                 priv->expander_style = g_value_get_enum (value);
186                 break;
187
188         case PROP_EXPANDER_SIZE:
189                 priv->expander_size = g_value_get_int (value);
190                 break;
191
192         case PROP_ACTIVATABLE:
193                 priv->activatable = g_value_get_boolean (value);
194                 break;
195
196         default:
197                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
198                 break;
199         }
200 }
201
202 static void
203 empathy_cell_renderer_expander_finalize (GObject *object)
204 {
205         (* G_OBJECT_CLASS (empathy_cell_renderer_expander_parent_class)->finalize) (object);
206 }
207
208 GtkCellRenderer *
209 empathy_cell_renderer_expander_new (void)
210 {
211         return g_object_new (EMPATHY_TYPE_CELL_RENDERER_EXPANDER, NULL);
212 }
213
214 static void
215 empathy_cell_renderer_expander_get_size (GtkCellRenderer    *cell,
216                                         GtkWidget          *widget,
217                                         const GdkRectangle *cell_area,
218                                         gint               *x_offset,
219                                         gint               *y_offset,
220                                         gint               *width,
221                                         gint               *height)
222 {
223         EmpathyCellRendererExpander     *expander;
224         EmpathyCellRendererExpanderPriv *priv;
225         gfloat xalign, yalign;
226         guint xpad, ypad;
227
228         expander = (EmpathyCellRendererExpander *) cell;
229         priv = GET_PRIV (expander);
230
231         g_object_get (cell,
232                       "xalign", &xalign,
233                       "yalign", &yalign,
234                       "xpad", &xpad,
235                       "ypad", &ypad,
236                       NULL);
237
238         if (cell_area) {
239                 if (x_offset) {
240                         *x_offset = xalign * (cell_area->width - (priv->expander_size + (2 * xpad)));
241                         *x_offset = MAX (*x_offset, 0);
242                 }
243
244                 if (y_offset) {
245                         *y_offset = yalign * (cell_area->height - (priv->expander_size + (2 * ypad)));
246                         *y_offset = MAX (*y_offset, 0);
247                 }
248         } else {
249                 if (x_offset)
250                         *x_offset = 0;
251
252                 if (y_offset)
253                         *y_offset = 0;
254         }
255
256         if (width)
257                 *width = xpad * 2 + priv->expander_size;
258
259         if (height)
260                 *height = ypad * 2 + priv->expander_size;
261 }
262
263 static void
264 empathy_cell_renderer_expander_render (GtkCellRenderer      *cell,
265                                       cairo_t *cr,
266                                       GtkWidget            *widget,
267                                       const GdkRectangle   *background_area,
268                                       const GdkRectangle   *cell_area,
269                                       GtkCellRendererState  flags)
270 {
271         EmpathyCellRendererExpander     *expander;
272         EmpathyCellRendererExpanderPriv *priv;
273         gint                            x_offset, y_offset;
274         guint                           xpad, ypad;
275         GtkStyleContext                 *style;
276         GtkStateFlags                    state;
277
278         expander = (EmpathyCellRendererExpander *) cell;
279         priv = GET_PRIV (expander);
280
281         empathy_cell_renderer_expander_get_size (cell, widget,
282                                                 (GdkRectangle *) cell_area,
283                                                 &x_offset, &y_offset,
284                                                 NULL, NULL);
285
286         g_object_get (cell,
287                       "xpad", &xpad,
288                       "ypad", &ypad,
289                       NULL);
290
291         style = gtk_widget_get_style_context (widget);
292
293         gtk_style_context_save (style);
294         gtk_style_context_add_class (style, GTK_STYLE_CLASS_EXPANDER);
295
296         state = gtk_cell_renderer_get_state (cell, widget, flags);
297
298         if (priv->expander_style == GTK_EXPANDER_COLLAPSED)
299                 state |= GTK_STATE_FLAG_NORMAL;
300         else
301                 state |= GTK_STATE_FLAG_ACTIVE;
302
303         gtk_style_context_set_state (style, state);
304
305         gtk_render_expander (style,
306                              cr,
307                              cell_area->x + x_offset + xpad,
308                              cell_area->y + y_offset + ypad,
309                              priv->expander_size,
310                              priv->expander_size);
311
312         gtk_style_context_restore (style);
313 }
314
315 static gboolean
316 empathy_cell_renderer_expander_activate (GtkCellRenderer      *cell,
317                                         GdkEvent             *event,
318                                         GtkWidget            *widget,
319                                         const gchar          *path_string,
320                                         const GdkRectangle   *background_area,
321                                         const GdkRectangle   *cell_area,
322                                         GtkCellRendererState  flags)
323 {
324         EmpathyCellRendererExpanderPriv *priv;
325         GtkTreePath                    *path;
326
327         priv = GET_PRIV (cell);
328
329         if (!GTK_IS_TREE_VIEW (widget) || !priv->activatable)
330                 return FALSE;
331
332         path = gtk_tree_path_new_from_string (path_string);
333
334         if (gtk_tree_path_get_depth (path) > 1) {
335                 gtk_tree_path_free (path);
336                 return TRUE;
337         }
338
339         if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) {
340                 gtk_tree_view_collapse_row (GTK_TREE_VIEW (widget), path);
341         } else {
342                 gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), path, FALSE);
343         }
344
345         gtk_tree_path_free (path);
346
347         return TRUE;
348 }