~ubuntu-branches/ubuntu/natty/ekiga/natty

« back to all changes in this revision

Viewing changes to lib/gui/gmcellrendererexpander.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2008-12-07 10:30:45 UTC
  • mfrom: (1.2.3 experimental)
  • Revision ID: james.westby@ubuntu.com-20081207103045-iaurrjo4p7d1nngo
Tags: 3.0.1-1ubuntu1
* Merge to Debian experimental, to get Ekiga 3. (LP: #274085) Remaining
  Ubuntu changes:
  - Launchpad Integration: (Ubuntu specific)
    + debian/control.in: Add liblaunchpad-integration-dev build dependency.
    + Add ubuntu_lpi.patch: Call launchpad_integration_add_items() in main() and
      check for the launchpad-integration pkg-config module.
    + Add autoconf.patch: autoconf changes from above patch.
  - Add ubuntu_desktop-file-onlyshowin.patch: Show ekiga in Mobile, too.
    (Ubuntu specific).
  - debian/control.in: Add missing fdupes build dependency for identical
    GNOME help file symlinking. (Debian #505536)
* Drop 42_change_pixmaps.dpatch: Many of the old icons do not exist any
  more, some have been replaced, and keeping the remaining three would make
  them look very inconsistent.
* Convert our dpatches to quilt patches and rewrite them for new upstream
  version.
* Add migrate_2.0_settings.patch: Properly migrate settings from
  2.0. Taken from upstream SVN, thanks to Damien Sandras!

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2006-2007 Imendio AB
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License as
 
6
 * published by the Free Software Foundation; either version 2 of the
 
7
 * License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public
 
15
 * License along with this program; if not, write to the
 
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 * Boston, MA 02111-1307, USA.
 
18
 * 
 
19
 * Authors: Kristian Rietveld <kris@imendio.com>
 
20
 */
 
21
 
 
22
/* To do:
 
23
 *  - should probably cancel animation if model changes
 
24
 *  - need to handle case where node-in-animation is removed
 
25
 *  - it only handles a single animation at a time; but I guess users
 
26
 *    aren't fast enough to trigger two or more animations at once anyway :P
 
27
 *    (could guard for this by just cancelling the "old" animation, and
 
28
 *     start the new one).
 
29
 */
 
30
 
 
31
#include <gtk/gtktreeview.h>
 
32
 
 
33
#include "gmcellrendererexpander.h"
 
34
 
 
35
#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GM_TYPE_CELL_RENDERER_EXPANDER, GmCellRendererExpanderPriv))
 
36
 
 
37
static void     gm_cell_renderer_expander_init         (GmCellRendererExpander      *expander);
 
38
static void     gm_cell_renderer_expander_class_init   (GmCellRendererExpanderClass *klass);
 
39
static void     gm_cell_renderer_expander_get_property (GObject                         *object,
 
40
                                                        guint                            param_id,
 
41
                                                        GValue                          *value,
 
42
                                                        GParamSpec                      *pspec);
 
43
static void     gm_cell_renderer_expander_set_property (GObject                         *object,
 
44
                                                        guint                            param_id,
 
45
                                                        const GValue                    *value,
 
46
                                                        GParamSpec                      *pspec);
 
47
static void     gm_cell_renderer_expander_finalize     (GObject                         *object);
 
48
static void     gm_cell_renderer_expander_get_size     (GtkCellRenderer                 *cell,
 
49
                                                        GtkWidget                       *widget,
 
50
                                                        GdkRectangle                    *cell_area,
 
51
                                                        gint                            *x_offset,
 
52
                                                        gint                            *y_offset,
 
53
                                                        gint                            *width,
 
54
                                                        gint                            *height);
 
55
static void     gm_cell_renderer_expander_render       (GtkCellRenderer                 *cell,
 
56
                                                        GdkWindow                       *window,
 
57
                                                        GtkWidget                       *widget,
 
58
                                                        GdkRectangle                    *background_area,
 
59
                                                        GdkRectangle                    *cell_area,
 
60
                                                        GdkRectangle                    *expose_area,
 
61
                                                        GtkCellRendererState             flags);
 
62
static gboolean gm_cell_renderer_expander_activate     (GtkCellRenderer                 *cell,
 
63
                                                        GdkEvent                        *event,
 
64
                                                        GtkWidget                       *widget,
 
65
                                                        const gchar                     *path,
 
66
                                                        GdkRectangle                    *background_area,
 
67
                                                        GdkRectangle                    *cell_area,
 
68
                                                        GtkCellRendererState             flags);
 
69
 
 
70
enum {
 
71
  PROP_0,
 
72
  PROP_EXPANDER_STYLE,
 
73
  PROP_EXPANDER_SIZE,
 
74
  PROP_ACTIVATABLE
 
75
};
 
76
 
 
77
typedef struct _GmCellRendererExpanderPriv GmCellRendererExpanderPriv;
 
78
 
 
79
struct _GmCellRendererExpanderPriv {
 
80
  GtkExpanderStyle     expander_style;
 
81
  gint                 expander_size;
 
82
 
 
83
  GtkTreeView         *animation_view;
 
84
  GtkTreeRowReference *animation_node;
 
85
  GtkExpanderStyle     animation_style;
 
86
  guint                animation_timeout;
 
87
  GdkRectangle         animation_area;
 
88
 
 
89
  guint                activatable : 1;
 
90
  guint                animation_expanding : 1;
 
91
};
 
92
 
 
93
G_DEFINE_TYPE (GmCellRendererExpander, gm_cell_renderer_expander, GTK_TYPE_CELL_RENDERER);
 
94
 
 
95
static void
 
96
gm_cell_renderer_expander_init (GmCellRendererExpander *expander)
 
97
{
 
98
  GmCellRendererExpanderPriv *priv;
 
99
 
 
100
  priv = GET_PRIV (expander);
 
101
 
 
102
  priv->expander_style = GTK_EXPANDER_COLLAPSED;
 
103
  priv->expander_size = 12;
 
104
  priv->activatable = TRUE;
 
105
  priv->animation_node = NULL;
 
106
 
 
107
  GTK_CELL_RENDERER (expander)->xpad = 2;
 
108
  GTK_CELL_RENDERER (expander)->ypad = 2;
 
109
  GTK_CELL_RENDERER (expander)->mode = GTK_CELL_RENDERER_MODE_ACTIVATABLE;
 
110
}
 
111
 
 
112
static void
 
113
gm_cell_renderer_expander_class_init (GmCellRendererExpanderClass *klass)
 
114
{
 
115
  GObjectClass         *object_class;
 
116
  GtkCellRendererClass *cell_class;
 
117
 
 
118
  object_class  = G_OBJECT_CLASS (klass);
 
119
  cell_class = GTK_CELL_RENDERER_CLASS (klass);
 
120
 
 
121
  object_class->finalize = gm_cell_renderer_expander_finalize;
 
122
 
 
123
  object_class->get_property = gm_cell_renderer_expander_get_property;
 
124
  object_class->set_property = gm_cell_renderer_expander_set_property;
 
125
 
 
126
  cell_class->get_size = gm_cell_renderer_expander_get_size;
 
127
  cell_class->render = gm_cell_renderer_expander_render;
 
128
  cell_class->activate = gm_cell_renderer_expander_activate;
 
129
 
 
130
  g_object_class_install_property (object_class,
 
131
                                   PROP_EXPANDER_STYLE,
 
132
                                   g_param_spec_enum ("expander-style",
 
133
                                                      "Expander Style",
 
134
                                                      "Style to use when painting the expander",
 
135
                                                      GTK_TYPE_EXPANDER_STYLE,
 
136
                                                      GTK_EXPANDER_COLLAPSED,
 
137
                                                      G_PARAM_READWRITE));
 
138
 
 
139
  g_object_class_install_property (object_class,
 
140
                                   PROP_EXPANDER_SIZE,
 
141
                                   g_param_spec_int ("expander-size",
 
142
                                                     "Expander Size",
 
143
                                                     "The size of the expander",
 
144
                                                     0,
 
145
                                                     G_MAXINT,
 
146
                                                     12,
 
147
                                                     G_PARAM_READWRITE));
 
148
 
 
149
  g_object_class_install_property (object_class,
 
150
                                   PROP_ACTIVATABLE,
 
151
                                   g_param_spec_boolean ("activatable",
 
152
                                                         "Activatable",
 
153
                                                         "The expander can be activated",
 
154
                                                         TRUE,
 
155
                                                         G_PARAM_READWRITE));
 
156
 
 
157
  g_type_class_add_private (object_class, sizeof (GmCellRendererExpanderPriv));
 
158
}
 
159
 
 
160
static void
 
161
gm_cell_renderer_expander_get_property (GObject    *object,
 
162
                                        guint       param_id,
 
163
                                        GValue     *value,
 
164
                                        GParamSpec *pspec)
 
165
{
 
166
  GmCellRendererExpander     *expander;
 
167
  GmCellRendererExpanderPriv *priv;
 
168
 
 
169
  expander = GM_CELL_RENDERER_EXPANDER (object);
 
170
  priv = GET_PRIV (expander);
 
171
 
 
172
  switch (param_id) {
 
173
  case PROP_EXPANDER_STYLE:
 
174
    g_value_set_enum (value, priv->expander_style);
 
175
    break;
 
176
 
 
177
  case PROP_EXPANDER_SIZE:
 
178
    g_value_set_int (value, priv->expander_size);
 
179
    break;
 
180
 
 
181
  case PROP_ACTIVATABLE:
 
182
    g_value_set_boolean (value, priv->activatable);
 
183
    break;
 
184
 
 
185
  default:
 
186
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 
187
    break;
 
188
  }
 
189
}
 
190
 
 
191
static void
 
192
gm_cell_renderer_expander_set_property (GObject      *object,
 
193
                                        guint         param_id,
 
194
                                        const GValue *value,
 
195
                                        GParamSpec   *pspec)
 
196
{
 
197
  GmCellRendererExpander     *expander;
 
198
  GmCellRendererExpanderPriv *priv;
 
199
 
 
200
  expander = GM_CELL_RENDERER_EXPANDER (object);
 
201
  priv = GET_PRIV (expander);
 
202
 
 
203
  switch (param_id) {
 
204
  case PROP_EXPANDER_STYLE:
 
205
    priv->expander_style = g_value_get_enum (value);
 
206
    break;
 
207
 
 
208
  case PROP_EXPANDER_SIZE:
 
209
    priv->expander_size = g_value_get_int (value);
 
210
    break;
 
211
 
 
212
  case PROP_ACTIVATABLE:
 
213
    priv->activatable = g_value_get_boolean (value);
 
214
    break;
 
215
 
 
216
  default:
 
217
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 
218
    break;
 
219
  }
 
220
}
 
221
 
 
222
static void
 
223
gm_cell_renderer_expander_finalize (GObject *object)
 
224
{
 
225
  GmCellRendererExpanderPriv *priv;
 
226
 
 
227
  priv = GET_PRIV (object);
 
228
 
 
229
  if (priv->animation_timeout) {
 
230
    g_source_remove (priv->animation_timeout);
 
231
    priv->animation_timeout = 0;
 
232
  }
 
233
 
 
234
  if (priv->animation_node) {
 
235
    gtk_tree_row_reference_free (priv->animation_node);
 
236
  }
 
237
 
 
238
  (* G_OBJECT_CLASS (gm_cell_renderer_expander_parent_class)->finalize) (object);
 
239
}
 
240
 
 
241
GtkCellRenderer *
 
242
gm_cell_renderer_expander_new (void)
 
243
{
 
244
  return g_object_new (GM_TYPE_CELL_RENDERER_EXPANDER, NULL);
 
245
}
 
246
 
 
247
static void
 
248
gm_cell_renderer_expander_get_size (GtkCellRenderer *cell,
 
249
                                    G_GNUC_UNUSED GtkWidget       *widget,
 
250
                                    GdkRectangle    *cell_area,
 
251
                                    gint            *x_offset,
 
252
                                    gint            *y_offset,
 
253
                                    gint            *width,
 
254
                                    gint            *height)
 
255
{
 
256
  GmCellRendererExpander     *expander;
 
257
  GmCellRendererExpanderPriv *priv;
 
258
 
 
259
  expander = (GmCellRendererExpander*) cell;
 
260
  priv = GET_PRIV (expander);
 
261
 
 
262
  if (cell_area) {
 
263
    if (x_offset) {
 
264
      *x_offset = cell->xalign * (cell_area->width - (priv->expander_size + (2 * cell->xpad)));
 
265
      *x_offset = MAX (*x_offset, 0);
 
266
    }
 
267
 
 
268
    if (y_offset) {
 
269
      *y_offset = cell->yalign * (cell_area->height - (priv->expander_size + (2 * cell->ypad)));
 
270
      *y_offset = MAX (*y_offset, 0);
 
271
    }
 
272
  } else {
 
273
    if (x_offset)
 
274
      *x_offset = 0;
 
275
 
 
276
    if (y_offset)
 
277
      *y_offset = 0;
 
278
  }
 
279
 
 
280
  if (width)
 
281
    *width = cell->xpad * 2 + priv->expander_size;
 
282
 
 
283
  if (height)
 
284
    *height = cell->ypad * 2 + priv->expander_size;
 
285
}
 
286
 
 
287
static void
 
288
gm_cell_renderer_expander_render (GtkCellRenderer      *cell,
 
289
                                  GdkWindow            *window,
 
290
                                  GtkWidget            *widget,
 
291
                                  GdkRectangle         *background_area,
 
292
                                  GdkRectangle         *cell_area,
 
293
                                  GdkRectangle         *expose_area,
 
294
                                  G_GNUC_UNUSED GtkCellRendererState  flags)
 
295
{
 
296
  GmCellRendererExpander     *expander;
 
297
  GmCellRendererExpanderPriv *priv;
 
298
  GtkExpanderStyle                expander_style;
 
299
  gint                            x_offset, y_offset;
 
300
 
 
301
  expander = (GmCellRendererExpander*) cell;
 
302
  priv = GET_PRIV (expander);
 
303
 
 
304
  if (priv->animation_node) {
 
305
    GtkTreePath *path;
 
306
    GdkRectangle rect;
 
307
 
 
308
    /* Not sure if I like this ... */
 
309
    path = gtk_tree_row_reference_get_path (priv->animation_node);
 
310
    gtk_tree_view_get_background_area (priv->animation_view, path,
 
311
                                       NULL, &rect);
 
312
    gtk_tree_path_free (path);
 
313
 
 
314
    if (background_area->y == rect.y)
 
315
      expander_style = priv->animation_style;
 
316
    else
 
317
      expander_style = priv->expander_style;
 
318
  } else
 
319
    expander_style = priv->expander_style;
 
320
 
 
321
  gm_cell_renderer_expander_get_size (cell, widget, cell_area,
 
322
                                      &x_offset, &y_offset,
 
323
                                      NULL, NULL);
 
324
 
 
325
  gtk_paint_expander (widget->style,
 
326
                      window,
 
327
                      GTK_STATE_NORMAL,
 
328
                      expose_area,
 
329
                      widget,
 
330
                      "treeview",
 
331
                      cell_area->x + x_offset + cell->xpad + priv->expander_size / 2,
 
332
                      cell_area->y + y_offset + cell->ypad + priv->expander_size / 2,
 
333
                      expander_style);
 
334
  gtk_paint_hline (widget->style, window, GTK_STATE_NORMAL, NULL, widget, NULL, 0,
 
335
                   widget->allocation.width, cell_area->y + cell_area->height);
 
336
}
 
337
 
 
338
static void
 
339
invalidate_node (GtkTreeView *tree_view,
 
340
                 GtkTreePath *path)
 
341
{
 
342
  GdkWindow    *bin_window;
 
343
  GdkRectangle  rect;
 
344
 
 
345
  bin_window = gtk_tree_view_get_bin_window (tree_view);
 
346
 
 
347
  gtk_tree_view_get_background_area (tree_view, path, NULL, &rect);
 
348
 
 
349
  rect.x = 0;
 
350
  rect.width = GTK_WIDGET (tree_view)->allocation.width;
 
351
 
 
352
  gdk_window_invalidate_rect (bin_window, &rect, TRUE);
 
353
}
 
354
 
 
355
static gboolean
 
356
do_animation (GmCellRendererExpander *expander)
 
357
{
 
358
  GmCellRendererExpanderPriv *priv;
 
359
  GtkTreePath                    *path;
 
360
  gboolean                        done = FALSE;
 
361
 
 
362
  priv = GET_PRIV (expander);
 
363
 
 
364
  if (priv->animation_expanding) {
 
365
    if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED)
 
366
      priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED;
 
367
    else if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED) {
 
368
      priv->animation_style = GTK_EXPANDER_EXPANDED;
 
369
      done = TRUE;
 
370
    }
 
371
  } else {
 
372
    if (priv->animation_style == GTK_EXPANDER_SEMI_EXPANDED)
 
373
      priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED;
 
374
    else if (priv->animation_style == GTK_EXPANDER_SEMI_COLLAPSED) {
 
375
      priv->animation_style = GTK_EXPANDER_COLLAPSED;
 
376
      done = TRUE;
 
377
    }
 
378
  }
 
379
 
 
380
  path = gtk_tree_row_reference_get_path (priv->animation_node);
 
381
  invalidate_node (priv->animation_view, path);
 
382
  gtk_tree_path_free (path);
 
383
 
 
384
  if (done) {
 
385
    gtk_tree_row_reference_free (priv->animation_node);
 
386
    priv->animation_node = NULL;
 
387
    priv->animation_timeout = 0;
 
388
  }
 
389
 
 
390
  return !done;
 
391
}
 
392
 
 
393
static gboolean
 
394
animation_timeout (gpointer data)
 
395
{
 
396
  gboolean retval;
 
397
 
 
398
  GDK_THREADS_ENTER ();
 
399
 
 
400
  retval = do_animation (data);
 
401
 
 
402
  GDK_THREADS_LEAVE ();
 
403
 
 
404
  return retval;
 
405
}
 
406
 
 
407
static void
 
408
gm_cell_renderer_expander_start_animation (GmCellRendererExpander *expander,
 
409
                                           GtkTreeView                *tree_view,
 
410
                                           GtkTreePath                *path,
 
411
                                           gboolean                    expanding,
 
412
                                           G_GNUC_UNUSED GdkRectangle               *background_area)
 
413
{
 
414
  GmCellRendererExpanderPriv *priv;
 
415
 
 
416
  priv = GET_PRIV (expander);
 
417
 
 
418
  if (expanding) {
 
419
    priv->animation_style = GTK_EXPANDER_SEMI_COLLAPSED;
 
420
  } else {
 
421
    priv->animation_style = GTK_EXPANDER_SEMI_EXPANDED;
 
422
  }
 
423
 
 
424
  invalidate_node (tree_view, path);
 
425
 
 
426
  priv->animation_expanding = expanding;
 
427
  priv->animation_view = tree_view;
 
428
  priv->animation_node = gtk_tree_row_reference_new (gtk_tree_view_get_model (tree_view), path);
 
429
  priv->animation_timeout = g_timeout_add (50, animation_timeout, expander);
 
430
}
 
431
 
 
432
static gboolean
 
433
gm_cell_renderer_expander_activate (GtkCellRenderer      *cell,
 
434
                                    G_GNUC_UNUSED GdkEvent             *event,
 
435
                                    GtkWidget            *widget,
 
436
                                    const gchar          *path_string,
 
437
                                    GdkRectangle         *background_area,
 
438
                                    G_GNUC_UNUSED GdkRectangle         *cell_area,
 
439
                                    G_GNUC_UNUSED GtkCellRendererState  flags)
 
440
{
 
441
  GmCellRendererExpander     *expander;
 
442
  GmCellRendererExpanderPriv *priv;
 
443
  GtkTreePath                    *path;
 
444
  gboolean                        animate;
 
445
  gboolean                        expanding;
 
446
 
 
447
  expander = GM_CELL_RENDERER_EXPANDER (cell);
 
448
  priv = GET_PRIV (cell);
 
449
 
 
450
  if (!GTK_IS_TREE_VIEW (widget) || !priv->activatable)
 
451
    return FALSE;
 
452
 
 
453
  path = gtk_tree_path_new_from_string (path_string);
 
454
 
 
455
  if (gtk_tree_path_get_depth (path) > 2) {
 
456
    gtk_tree_path_free (path);
 
457
    return TRUE;
 
458
  }
 
459
 
 
460
  g_object_get (gtk_widget_get_settings (GTK_WIDGET (widget)),
 
461
                "gtk-enable-animations", &animate,
 
462
                NULL);
 
463
 
 
464
  if (gtk_tree_view_row_expanded (GTK_TREE_VIEW (widget), path)) {
 
465
    gtk_tree_view_collapse_row (GTK_TREE_VIEW (widget), path);
 
466
    expanding = FALSE;
 
467
  } else {
 
468
    gtk_tree_view_expand_row (GTK_TREE_VIEW (widget), path, FALSE);
 
469
    expanding = TRUE;
 
470
  }
 
471
 
 
472
  if (animate) {
 
473
    gm_cell_renderer_expander_start_animation (expander,
 
474
                                               GTK_TREE_VIEW (widget),
 
475
                                               path,
 
476
                                               expanding,
 
477
                                               background_area);
 
478
  }
 
479
 
 
480
  gtk_tree_path_free (path);
 
481
 
 
482
  return TRUE;
 
483
}