]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-cell-renderer-text.c
cell_renderer_text_render: update to new API
[empathy.git] / libempathy-gtk / empathy-cell-renderer-text.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2004-2007 Imendio AB
4  * Copyright (C) 2010 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: Mikael Hallendal <micke@imendio.com>
22  */
23
24 #include "config.h"
25
26 #include <string.h>
27
28 #include <libempathy/empathy-utils.h>
29 #include "empathy-cell-renderer-text.h"
30
31 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyCellRendererText)
32 typedef struct {
33         gchar    *name;
34         TpConnectionPresenceType presence_type;
35         gchar    *status;
36         gboolean  is_group;
37
38         gboolean  is_valid;
39         gboolean  is_selected;
40
41         gboolean  compact;
42 } EmpathyCellRendererTextPriv;
43
44 static void cell_renderer_text_finalize          (GObject                     *object);
45 static void cell_renderer_text_get_property      (GObject                     *object,
46                                                   guint                        param_id,
47                                                   GValue                      *value,
48                                                   GParamSpec                  *pspec);
49 static void cell_renderer_text_set_property      (GObject                     *object,
50                                                   guint                        param_id,
51                                                   const GValue                *value,
52                                                   GParamSpec                  *pspec);
53 static void cell_renderer_text_get_size          (GtkCellRenderer             *cell,
54                                                   GtkWidget                   *widget,
55                                                   GdkRectangle                *cell_area,
56                                                   gint                        *x_offset,
57                                                   gint                        *y_offset,
58                                                   gint                        *width,
59                                                   gint                        *height);
60 static void cell_renderer_text_render            (GtkCellRenderer             *cell,
61                                                   cairo_t *cr,
62                                                   GtkWidget                   *widget,
63                                                   const GdkRectangle          *background_area,
64                                                   const GdkRectangle          *cell_area,
65                                                   GtkCellRendererState         flags);
66 static void cell_renderer_text_update_text       (EmpathyCellRendererText      *cell,
67                                                   GtkWidget                   *widget,
68                                                   gboolean                     selected);
69
70 /* Properties */
71 enum {
72         PROP_0,
73         PROP_NAME,
74         PROP_PRESENCE_TYPE,
75         PROP_STATUS,
76         PROP_IS_GROUP,
77         PROP_COMPACT
78 };
79
80 G_DEFINE_TYPE (EmpathyCellRendererText, empathy_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
81
82 static void
83 empathy_cell_renderer_text_class_init (EmpathyCellRendererTextClass *klass)
84 {
85         GObjectClass         *object_class;
86         GtkCellRendererClass *cell_class;
87         GParamSpec           *spec;
88
89         object_class = G_OBJECT_CLASS (klass);
90         cell_class = GTK_CELL_RENDERER_CLASS (klass);
91
92         object_class->finalize = cell_renderer_text_finalize;
93
94         object_class->get_property = cell_renderer_text_get_property;
95         object_class->set_property = cell_renderer_text_set_property;
96
97         cell_class->get_size = cell_renderer_text_get_size;
98         cell_class->render = cell_renderer_text_render;
99
100         spec = g_param_spec_string ("name", "Name", "Contact name", NULL,
101                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
102         g_object_class_install_property (object_class, PROP_NAME, spec);
103
104         spec = g_param_spec_uint ("presence-type", "TpConnectionPresenceType",
105                 "The contact's presence type",
106                 0, G_MAXUINT, /* Telepathy enum, can be extended */
107                 TP_CONNECTION_PRESENCE_TYPE_UNKNOWN,
108                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
109         g_object_class_install_property (object_class, PROP_PRESENCE_TYPE,
110                 spec);
111
112         spec = g_param_spec_string ("status", "Status message",
113                 "Contact's custom status message", NULL,
114                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
115         g_object_class_install_property (object_class, PROP_STATUS, spec);
116
117         spec = g_param_spec_boolean ("is-group", "Is group",
118                 "Whether this cell is a group", FALSE,
119                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
120         g_object_class_install_property (object_class, PROP_IS_GROUP, spec);
121
122         spec = g_param_spec_boolean ("compact", "Compact",
123                 "TRUE to show the status alongside the contact name;"
124                 "FALSE to show it on its own line",
125                 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
126         g_object_class_install_property (object_class, PROP_COMPACT, spec);
127
128         g_type_class_add_private (object_class, sizeof (EmpathyCellRendererTextPriv));
129 }
130
131 static void
132 empathy_cell_renderer_text_init (EmpathyCellRendererText *cell)
133 {
134         EmpathyCellRendererTextPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (cell,
135                 EMPATHY_TYPE_CELL_RENDERER_TEXT, EmpathyCellRendererTextPriv);
136
137         cell->priv = priv;
138         g_object_set (cell,
139                       "ellipsize", PANGO_ELLIPSIZE_END,
140                       NULL);
141
142         priv->name = g_strdup ("");
143         priv->status = g_strdup ("");
144         priv->compact = FALSE;
145 }
146
147 static void
148 cell_renderer_text_finalize (GObject *object)
149 {
150         EmpathyCellRendererText     *cell;
151         EmpathyCellRendererTextPriv *priv;
152
153         cell = EMPATHY_CELL_RENDERER_TEXT (object);
154         priv = GET_PRIV (cell);
155
156         g_free (priv->name);
157         g_free (priv->status);
158
159         (G_OBJECT_CLASS (empathy_cell_renderer_text_parent_class)->finalize) (object);
160 }
161
162 static void
163 cell_renderer_text_get_property (GObject    *object,
164                                  guint       param_id,
165                                  GValue     *value,
166                                  GParamSpec *pspec)
167 {
168         EmpathyCellRendererText     *cell;
169         EmpathyCellRendererTextPriv *priv;
170
171         cell = EMPATHY_CELL_RENDERER_TEXT (object);
172         priv = GET_PRIV (cell);
173
174         switch (param_id) {
175         case PROP_NAME:
176                 g_value_set_string (value, priv->name);
177                 break;
178         case PROP_PRESENCE_TYPE:
179                 g_value_set_uint (value, priv->presence_type);
180                 break;
181         case PROP_STATUS:
182                 g_value_set_string (value, priv->status);
183                 break;
184         case PROP_IS_GROUP:
185                 g_value_set_boolean (value, priv->is_group);
186                 break;
187         case PROP_COMPACT:
188                 g_value_set_boolean (value, priv->compact);
189                 break;
190         default:
191                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
192                 break;
193         }
194 }
195
196 static void
197 cell_renderer_text_set_property (GObject      *object,
198                                  guint         param_id,
199                                  const GValue *value,
200                                  GParamSpec   *pspec)
201 {
202         EmpathyCellRendererText     *cell;
203         EmpathyCellRendererTextPriv *priv;
204         const gchar                *str;
205
206         cell = EMPATHY_CELL_RENDERER_TEXT (object);
207         priv = GET_PRIV (cell);
208
209         switch (param_id) {
210         case PROP_NAME:
211                 g_free (priv->name);
212                 str = g_value_get_string (value);
213                 priv->name = g_strdup (str ? str : "");
214                 g_strdelimit (priv->name, "\n\r\t", ' ');
215                 priv->is_valid = FALSE;
216                 break;
217         case PROP_PRESENCE_TYPE:
218                 priv->presence_type = g_value_get_uint (value);
219                 priv->is_valid = FALSE;
220                 break;
221         case PROP_STATUS:
222                 g_free (priv->status);
223                 str = g_value_get_string (value);
224                 priv->status = g_strdup (str ? str : "");
225                 g_strdelimit (priv->status, "\n\r\t", ' ');
226                 priv->is_valid = FALSE;
227                 break;
228         case PROP_IS_GROUP:
229                 priv->is_group = g_value_get_boolean (value);
230                 priv->is_valid = FALSE;
231                 break;
232         case PROP_COMPACT:
233                 priv->compact = g_value_get_boolean (value);
234                 priv->is_valid = FALSE;
235                 break;
236         default:
237                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
238                 break;
239         }
240 }
241
242 static void
243 cell_renderer_text_get_size (GtkCellRenderer *cell,
244                              GtkWidget       *widget,
245                              GdkRectangle    *cell_area,
246                              gint            *x_offset,
247                              gint            *y_offset,
248                              gint            *width,
249                              gint            *height)
250 {
251         EmpathyCellRendererText     *celltext;
252         EmpathyCellRendererTextPriv *priv;
253
254         celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
255         priv = GET_PRIV (cell);
256
257         /* Only update if not already valid so we get the right size. */
258         cell_renderer_text_update_text (celltext, widget, priv->is_selected);
259
260         (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->get_size) (cell, widget,
261                                                                                       cell_area,
262                                                                                       x_offset, y_offset,
263                                                                                       width, height);
264 }
265
266 static void
267 cell_renderer_text_render (GtkCellRenderer      *cell,
268                            cairo_t *cr,
269                            GtkWidget            *widget,
270                            const GdkRectangle   *background_area,
271                            const GdkRectangle   *cell_area,
272                            GtkCellRendererState  flags)
273 {
274         EmpathyCellRendererText *celltext;
275
276         celltext = EMPATHY_CELL_RENDERER_TEXT (cell);
277
278         cell_renderer_text_update_text (celltext,
279                                         widget,
280                                         (flags & GTK_CELL_RENDERER_SELECTED));
281
282         (GTK_CELL_RENDERER_CLASS (empathy_cell_renderer_text_parent_class)->render) (
283                 cell, cr,
284                 widget,
285                 background_area,
286                 cell_area,
287                 flags);
288 }
289
290 static void
291 cell_renderer_text_update_text (EmpathyCellRendererText *cell,
292                                 GtkWidget              *widget,
293                                 gboolean                selected)
294 {
295         EmpathyCellRendererTextPriv *priv;
296         PangoAttrList              *attr_list;
297         PangoAttribute             *attr_color, *attr_size;
298         GtkStyle                   *style;
299         gchar                      *str;
300
301         priv = GET_PRIV (cell);
302
303         if (priv->is_valid && priv->is_selected == selected) {
304                 return;
305         }
306
307         if (priv->is_group) {
308                 g_object_set (cell,
309                               "visible", TRUE,
310                               "weight", PANGO_WEIGHT_BOLD,
311                               "text", priv->name,
312                               "attributes", NULL,
313                               "xpad", 1,
314                               "ypad", 1,
315                               NULL);
316
317                 priv->is_selected = selected;
318                 priv->is_valid = TRUE;
319                 return;
320         }
321
322         style = gtk_widget_get_style (widget);
323
324         attr_list = pango_attr_list_new ();
325
326         attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2);
327         attr_size->start_index = strlen (priv->name) + 1;
328         attr_size->end_index = -1;
329         pango_attr_list_insert (attr_list, attr_size);
330
331         if (!selected) {
332                 GdkColor color;
333
334                 color = style->text_aa[GTK_STATE_NORMAL];
335
336                 attr_color = pango_attr_foreground_new (color.red, color.green, color.blue);
337                 attr_color->start_index = attr_size->start_index;
338                 attr_color->end_index = -1;
339                 pango_attr_list_insert (attr_list, attr_color);
340         }
341
342         if (priv->compact) {
343                 if (EMP_STR_EMPTY (priv->status)) {
344                         str = g_strdup (priv->name);
345                 } else {
346                         str = g_strdup_printf ("%s %s", priv->name, priv->status);
347                 }
348         } else {
349                 const gchar *status = priv->status;
350
351                 if (EMP_STR_EMPTY (priv->status)) {
352                         status = empathy_presence_get_default_message (priv->presence_type);
353                 }
354
355                 if (status == NULL)
356                         str = g_strdup (priv->name);
357                 else
358                         str = g_strdup_printf ("%s\n%s", priv->name, status);
359         }
360
361         g_object_set (cell,
362                       "visible", TRUE,
363                       "weight", PANGO_WEIGHT_NORMAL,
364                       "text", str,
365                       "attributes", attr_list,
366                       "xpad", 0,
367                       "ypad", 1,
368                       NULL);
369
370         g_free (str);
371         pango_attr_list_unref (attr_list);
372
373         priv->is_selected = selected;
374         priv->is_valid = TRUE;
375 }
376
377 GtkCellRenderer *
378 empathy_cell_renderer_text_new (void)
379 {
380         return g_object_new (EMPATHY_TYPE_CELL_RENDERER_TEXT, NULL);
381 }