]> git.0d.be Git - empathy.git/blob - libempathy-gtk/gossip-cell-renderer-text.c
[darcs-to-svn @ Save/restore window geometry]
[empathy.git] / libempathy-gtk / gossip-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  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * Authors: Mikael Hallendal <micke@imendio.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include "gossip-cell-renderer-text.h"
28
29 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CELL_RENDERER_TEXT, GossipCellRendererTextPriv))
30
31 struct _GossipCellRendererTextPriv {
32         gchar    *name;
33         gchar    *status;
34         gboolean  is_group;
35
36         gboolean  is_valid;
37         gboolean  is_selected;
38
39         gboolean  show_status;
40 };
41
42 static void gossip_cell_renderer_text_class_init (GossipCellRendererTextClass *klass);
43 static void gossip_cell_renderer_text_init       (GossipCellRendererText      *cell);
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                                                   GdkDrawable                 *window,
62                                                   GtkWidget                   *widget,
63                                                   GdkRectangle                *background_area,
64                                                   GdkRectangle                *cell_area,
65                                                   GdkRectangle                *expose_area,
66                                                   GtkCellRendererState         flags);
67 static void cell_renderer_text_update_text       (GossipCellRendererText      *cell,
68                                                   GtkWidget                   *widget,
69                                                   gboolean                     selected);
70
71 /* Properties */
72 enum {
73         PROP_0,
74         PROP_NAME,
75         PROP_STATUS,
76         PROP_IS_GROUP,
77         PROP_SHOW_STATUS,
78 };
79
80 G_DEFINE_TYPE (GossipCellRendererText, gossip_cell_renderer_text, GTK_TYPE_CELL_RENDERER_TEXT);
81
82 static void
83 gossip_cell_renderer_text_class_init (GossipCellRendererTextClass *klass)
84 {
85         GObjectClass         *object_class;
86         GtkCellRendererClass *cell_class;
87
88         object_class = G_OBJECT_CLASS (klass);
89         cell_class = GTK_CELL_RENDERER_CLASS (klass);
90
91         object_class->finalize = cell_renderer_text_finalize;
92
93         object_class->get_property = cell_renderer_text_get_property;
94         object_class->set_property = cell_renderer_text_set_property;
95
96         cell_class->get_size = cell_renderer_text_get_size;
97         cell_class->render = cell_renderer_text_render;
98
99         g_object_class_install_property (object_class,
100                                          PROP_NAME,
101                                          g_param_spec_string ("name",
102                                                               "Name",
103                                                               "Contact name",
104                                                               NULL,
105                                                               G_PARAM_READWRITE));
106         g_object_class_install_property (object_class,
107                                          PROP_STATUS,
108                                          g_param_spec_string ("status",
109                                                               "Status",
110                                                               "Contact status string",
111                                                               NULL,
112                                                               G_PARAM_READWRITE));
113         g_object_class_install_property (object_class,
114                                          PROP_IS_GROUP,
115                                          g_param_spec_boolean ("is_group",
116                                                                "Is group",
117                                                                "Whether this cell is a group",
118                                                                FALSE,
119                                                                G_PARAM_READWRITE));
120         g_object_class_install_property (object_class,
121                                          PROP_SHOW_STATUS,
122                                          g_param_spec_boolean ("show-status",
123                                                                "Show status",
124                                                                "Whether to show the status line",
125                                                                TRUE,
126                                                                G_PARAM_READWRITE));
127
128         g_type_class_add_private (object_class, sizeof (GossipCellRendererTextPriv));
129 }
130
131 static void
132 gossip_cell_renderer_text_init (GossipCellRendererText *cell)
133 {
134         GossipCellRendererTextPriv *priv;
135
136         priv = GET_PRIV (cell);
137
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->show_status = TRUE;
145 }
146
147 static void
148 cell_renderer_text_finalize (GObject *object)
149 {
150         GossipCellRendererText     *cell;
151         GossipCellRendererTextPriv *priv;
152
153         cell = GOSSIP_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 (gossip_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         GossipCellRendererText     *cell;
169         GossipCellRendererTextPriv *priv;
170
171         cell = GOSSIP_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_STATUS:
179                 g_value_set_string (value, priv->status);
180                 break;
181         case PROP_IS_GROUP:
182                 g_value_set_boolean (value, priv->is_group);
183                 break;
184         case PROP_SHOW_STATUS:
185                 g_value_set_boolean (value, priv->show_status);
186                 break;
187         default:
188                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
189                 break;
190         }
191 }
192
193 static void
194 cell_renderer_text_set_property (GObject      *object,
195                                  guint         param_id,
196                                  const GValue *value,
197                                  GParamSpec   *pspec)
198 {
199         GossipCellRendererText     *cell;
200         GossipCellRendererTextPriv *priv;
201         const gchar                *str;
202
203         cell = GOSSIP_CELL_RENDERER_TEXT (object);
204         priv = GET_PRIV (cell);
205
206         switch (param_id) {
207         case PROP_NAME:
208                 g_free (priv->name);
209                 str = g_value_get_string (value);
210                 priv->name = g_strdup (str ? str : "");
211                 g_strdelimit (priv->name, "\n\r\t", ' ');
212                 priv->is_valid = FALSE;
213                 break;
214         case PROP_STATUS:
215                 g_free (priv->status);
216                 str = g_value_get_string (value);
217                 priv->status = g_strdup (str ? str : "");
218                 g_strdelimit (priv->status, "\n\r\t", ' ');
219                 priv->is_valid = FALSE;
220                 break;
221         case PROP_IS_GROUP:
222                 priv->is_group = g_value_get_boolean (value);
223                 priv->is_valid = FALSE;
224                 break;
225         case PROP_SHOW_STATUS:
226                 priv->show_status = g_value_get_boolean (value);
227                 priv->is_valid = FALSE;
228                 break;
229         default:
230                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
231                 break;
232         }
233 }
234
235 static void
236 cell_renderer_text_get_size (GtkCellRenderer *cell,
237                              GtkWidget       *widget,
238                              GdkRectangle    *cell_area,
239                              gint            *x_offset,
240                              gint            *y_offset,
241                              gint            *width,
242                              gint            *height)
243 {
244         GossipCellRendererText     *celltext;
245         GossipCellRendererTextPriv *priv;
246
247         celltext = GOSSIP_CELL_RENDERER_TEXT (cell);
248         priv = GET_PRIV (cell);
249
250         /* Only update if not already valid so we get the right size. */
251         cell_renderer_text_update_text (celltext, widget, priv->is_selected);
252
253         (GTK_CELL_RENDERER_CLASS (gossip_cell_renderer_text_parent_class)->get_size) (cell, widget,
254                                                                                       cell_area,
255                                                                                       x_offset, y_offset,
256                                                                                       width, height);
257 }
258
259 static void
260 cell_renderer_text_render (GtkCellRenderer      *cell,
261                            GdkWindow            *window,
262                            GtkWidget            *widget,
263                            GdkRectangle         *background_area,
264                            GdkRectangle         *cell_area,
265                            GdkRectangle         *expose_area,
266                            GtkCellRendererState  flags)
267 {
268         GossipCellRendererText *celltext;
269
270         celltext = GOSSIP_CELL_RENDERER_TEXT (cell);
271
272         cell_renderer_text_update_text (celltext,
273                                         widget,
274                                         (flags & GTK_CELL_RENDERER_SELECTED));
275
276         (GTK_CELL_RENDERER_CLASS (gossip_cell_renderer_text_parent_class)->render) (
277                 cell, window,
278                 widget,
279                 background_area,
280                 cell_area,
281                 expose_area, flags);
282 }
283
284 static void
285 cell_renderer_text_update_text (GossipCellRendererText *cell,
286                                 GtkWidget              *widget,
287                                 gboolean                selected)
288 {
289         GossipCellRendererTextPriv *priv;
290         PangoAttrList              *attr_list;
291         PangoAttribute             *attr_color, *attr_style, *attr_size;
292         GtkStyle                   *style;
293         gchar                      *str;
294
295         priv = GET_PRIV (cell);
296
297         if (priv->is_valid && priv->is_selected == selected) {
298                 return;
299         }
300
301         if (priv->is_group) {
302                 g_object_set (cell,
303                               "visible", TRUE,
304                               "weight", PANGO_WEIGHT_BOLD,
305                               "text", priv->name,
306                               "attributes", NULL,
307                               "xpad", 1,
308                               "ypad", 1,
309                               NULL);
310
311                 priv->is_selected = selected;
312                 priv->is_valid = TRUE;
313                 return;
314         }
315
316         style = gtk_widget_get_style (widget);
317
318         attr_list = pango_attr_list_new ();
319
320         attr_style = pango_attr_style_new (PANGO_STYLE_ITALIC);
321         attr_style->start_index = strlen (priv->name) + 1;
322         attr_style->end_index = -1;
323         pango_attr_list_insert (attr_list, attr_style);
324
325         if (!selected) {
326                 GdkColor color;
327
328                 color = style->text_aa[GTK_STATE_NORMAL];
329
330                 attr_color = pango_attr_foreground_new (color.red, color.green, color.blue);
331                 attr_color->start_index = attr_style->start_index;
332                 attr_color->end_index = -1;
333                 pango_attr_list_insert (attr_list, attr_color);
334         }
335
336         attr_size = pango_attr_size_new (pango_font_description_get_size (style->font_desc) / 1.2);
337
338         attr_size->start_index = attr_style->start_index;
339         attr_size->end_index = -1;
340         pango_attr_list_insert (attr_list, attr_size);
341
342         if (!priv->status || !priv->status[0] || !priv->show_status) {
343                 str = g_strdup (priv->name);
344         } else {
345                 str = g_strdup_printf ("%s\n%s", priv->name, priv->status);
346         }
347
348         g_object_set (cell,
349                       "visible", TRUE,
350                       "weight", PANGO_WEIGHT_NORMAL,
351                       "text", str,
352                       "attributes", attr_list,
353                       "xpad", 0,
354                       "ypad", 1,
355                       NULL);
356
357         g_free (str);
358         pango_attr_list_unref (attr_list);
359
360         priv->is_selected = selected;
361         priv->is_valid = TRUE;
362 }
363
364 GtkCellRenderer *
365 gossip_cell_renderer_text_new (void)
366 {
367         return g_object_new (GOSSIP_TYPE_CELL_RENDERER_TEXT, NULL);
368 }