~ubuntu-branches/debian/experimental/inkscape/experimental

« back to all changes in this revision

Viewing changes to src/libgdl/gdl-switcher.c

  • Committer: Bazaar Package Importer
  • Author(s): Thomas Viehmann
  • Date: 2008-09-09 23:29:02 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20080909232902-c50iujhk1w79u8e7
Tags: 0.46-2.1
* Non-maintainer upload.
* Add upstream patch fixing a crash in the open dialog
  in the zh_CN.utf8 locale. Closes: #487623.
  Thanks to Luca Bruno for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 8 -*- */
 
2
/* gdl-switcher.c
 
3
 *
 
4
 * Copyright (C) 2003  Ettore Perazzoli,
 
5
 *               2007  Naba Kumar
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or
 
8
 * modify it under the terms of version 2 of the GNU General Public
 
9
 * License as published by the Free Software Foundation.
 
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., 59 Temple Place - Suite 330,
 
19
 * Boston, MA 02111-1307, USA.
 
20
 *
 
21
 * Copied and adapted from ESidebar.[ch] from evolution
 
22
 * 
 
23
 * Authors: Ettore Perazzoli <ettore@ximian.com>
 
24
 *          Naba Kumar  <naba@gnome.org>
 
25
 */
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#include <config.h>
 
29
#endif
 
30
 
 
31
#include "gdl-i18n.h"
 
32
#include "gdl-switcher.h"
 
33
#include "gdl-tools.h"
 
34
#include "libgdlmarshal.h"
 
35
#include "libgdltypebuiltins.h"
 
36
 
 
37
#include <gtk/gtk.h>
 
38
#include <gtk/gtkhbox.h>
 
39
#include <gtk/gtkimage.h>
 
40
#include <gtk/gtklabel.h>
 
41
#include <gtk/gtktogglebutton.h>
 
42
 
 
43
#if HAVE_GNOME
 
44
#include <gconf/gconf-client.h>
 
45
#include <libgnome/gnome-gconf.h>
 
46
#endif
 
47
 
 
48
static void gdl_switcher_set_property  (GObject            *object,
 
49
                                        guint               prop_id,
 
50
                                        const GValue       *value,
 
51
                                        GParamSpec         *pspec);
 
52
static void gdl_switcher_get_property  (GObject            *object,
 
53
                                        guint               prop_id,
 
54
                                        GValue             *value,
 
55
                                        GParamSpec         *pspec);
 
56
 
 
57
static void gdl_switcher_add_button  (GdlSwitcher *switcher,
 
58
                                      const gchar *label,
 
59
                                      const gchar *tooltips,
 
60
                                      const gchar *stock_id,
 
61
                                      const GdkPixbuf *pixbuf_icon,
 
62
                                      gint switcher_id);
 
63
static void gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id);
 
64
static void gdl_switcher_select_page (GdlSwitcher *switcher, gint switcher_id);
 
65
static void gdl_switcher_select_button (GdlSwitcher *switcher, gint switcher_id);
 
66
static void gdl_switcher_set_show_buttons (GdlSwitcher *switcher, gboolean show);
 
67
static void gdl_switcher_set_style (GdlSwitcher *switcher,
 
68
                                    GdlSwitcherStyle switcher_style);
 
69
static GdlSwitcherStyle gdl_switcher_get_style (GdlSwitcher *switcher);
 
70
 
 
71
enum {
 
72
    PROP_0,
 
73
    PROP_SWITCHER_STYLE
 
74
};
 
75
 
 
76
typedef struct {
 
77
    GtkWidget *button_widget;
 
78
    GtkWidget *label;
 
79
    GtkWidget *icon;
 
80
    GtkWidget *arrow;
 
81
    GtkWidget *hbox;
 
82
    GtkTooltips *tooltips;
 
83
    int id;
 
84
} Button;
 
85
 
 
86
struct _GdlSwitcherPrivate {
 
87
    GdlSwitcherStyle switcher_style;
 
88
    GdlSwitcherStyle toolbar_style;
 
89
    
 
90
    gboolean show;
 
91
    GSList *buttons;
 
92
 
 
93
    guint style_changed_id;
 
94
    gint buttons_height_request;
 
95
    gboolean in_toggle;
 
96
};
 
97
 
 
98
GDL_CLASS_BOILERPLATE (GdlSwitcher, gdl_switcher, GtkNotebook, GTK_TYPE_NOTEBOOK)
 
99
 
 
100
#define INTERNAL_MODE(switcher)  (switcher->priv->switcher_style == \
 
101
            GDL_SWITCHER_STYLE_TOOLBAR ? switcher->priv->toolbar_style : \
 
102
            switcher->priv->switcher_style)
 
103
 
 
104
#define H_PADDING 2
 
105
#define V_PADDING 2
 
106
 
 
107
/* Utility functions.  */
 
108
 
 
109
static Button *
 
110
button_new (GtkWidget *button_widget, GtkWidget *label, GtkWidget *icon,
 
111
            GtkTooltips *tooltips, GtkWidget *arrow, GtkWidget *hbox, int id)
 
112
{
 
113
    Button *button = g_new (Button, 1);
 
114
 
 
115
    button->button_widget = button_widget;
 
116
    button->label = label;
 
117
    button->icon = icon;
 
118
    button->arrow = arrow;
 
119
    button->hbox = hbox;
 
120
    button->tooltips = tooltips;
 
121
    button->id = id;
 
122
 
 
123
    g_object_ref (button_widget);
 
124
    g_object_ref (label);
 
125
    g_object_ref (icon);
 
126
    g_object_ref (arrow);
 
127
    g_object_ref (hbox);
 
128
    g_object_ref (tooltips);
 
129
 
 
130
    return button;
 
131
}
 
132
 
 
133
static void
 
134
button_free (Button *button)
 
135
{
 
136
    g_object_unref (button->button_widget);
 
137
    g_object_unref (button->label);
 
138
    g_object_unref (button->icon);
 
139
    g_object_unref (button->hbox);
 
140
    g_object_unref (button->tooltips);
 
141
    g_free (button);
 
142
}
 
143
 
 
144
static gint
 
145
gdl_switcher_get_page_id (GtkWidget *widget)
 
146
{
 
147
    static gint switcher_id_count = 0;
 
148
    gint switcher_id;
 
149
    switcher_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
 
150
                                                      "__switcher_id"));
 
151
    if (switcher_id <= 0) {
 
152
        switcher_id = ++switcher_id_count;
 
153
        g_object_set_data (G_OBJECT (widget), "__switcher_id",
 
154
                           GINT_TO_POINTER (switcher_id));
 
155
    }
 
156
    return switcher_id;
 
157
}
 
158
 
 
159
static void
 
160
update_buttons (GdlSwitcher *switcher, int new_selected_id)
 
161
{
 
162
    GSList *p;
 
163
 
 
164
    switcher->priv->in_toggle = TRUE;
 
165
 
 
166
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
167
        Button *button = p->data;
 
168
 
 
169
        if (button->id == new_selected_id) {
 
170
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
 
171
                                          (button->button_widget), TRUE);
 
172
            gtk_widget_set_sensitive (button->arrow, TRUE);
 
173
        } else {
 
174
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
 
175
                                          (button->button_widget), FALSE);
 
176
            gtk_widget_set_sensitive (button->arrow, FALSE);
 
177
        }
 
178
    }
 
179
 
 
180
    switcher->priv->in_toggle = FALSE;
 
181
}
 
182
 
 
183
/* Callbacks.  */
 
184
 
 
185
static void
 
186
button_toggled_callback (GtkToggleButton *toggle_button,
 
187
                         GdlSwitcher *switcher)
 
188
{
 
189
    int id = 0;
 
190
    gboolean is_active = FALSE;
 
191
    GSList *p;
 
192
 
 
193
    if (switcher->priv->in_toggle)
 
194
        return;
 
195
 
 
196
    switcher->priv->in_toggle = TRUE;
 
197
 
 
198
    if (gtk_toggle_button_get_active (toggle_button))
 
199
        is_active = TRUE;
 
200
 
 
201
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
202
        Button *button = p->data;
 
203
 
 
204
        if (button->button_widget != GTK_WIDGET (toggle_button)) {
 
205
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
 
206
                                          (button->button_widget), FALSE);
 
207
            gtk_widget_set_sensitive (button->arrow, FALSE);
 
208
        } else {
 
209
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
 
210
                                          (button->button_widget), TRUE);
 
211
            gtk_widget_set_sensitive (button->arrow, TRUE);
 
212
            id = button->id;
 
213
        }
 
214
    }
 
215
    
 
216
    switcher->priv->in_toggle = FALSE;
 
217
 
 
218
    if (is_active)
 
219
    {
 
220
        gdl_switcher_select_page (switcher, id);
 
221
    }
 
222
}
 
223
 
 
224
/* Returns -1 if layout didn't happen because a resize request was queued */
 
225
static int
 
226
layout_buttons (GdlSwitcher *switcher)
 
227
{
 
228
    GtkRequisition client_requisition;
 
229
    GtkAllocation *allocation = & GTK_WIDGET (switcher)->allocation;
 
230
    GdlSwitcherStyle switcher_style;
 
231
    gboolean icons_only;
 
232
    int num_btns = g_slist_length (switcher->priv->buttons);
 
233
    int btns_per_row;
 
234
    GSList **rows, *p;
 
235
    Button *button;
 
236
    int row_number;
 
237
    int max_btn_width = 0, max_btn_height = 0;
 
238
    int optimal_layout_width = 0;
 
239
    int row_last;
 
240
    int x, y;
 
241
    int i;
 
242
    int rows_count;
 
243
    int last_buttons_height;
 
244
    
 
245
    last_buttons_height = switcher->priv->buttons_height_request;
 
246
    
 
247
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, size_request,
 
248
                     (GTK_WIDGET (switcher), &client_requisition));
 
249
 
 
250
    y = allocation->y + allocation->height - V_PADDING - 1;
 
251
 
 
252
    if (num_btns == 0)
 
253
        return y;
 
254
 
 
255
    switcher_style = INTERNAL_MODE (switcher);
 
256
    icons_only = (switcher_style == GDL_SWITCHER_STYLE_ICON);
 
257
    
 
258
    /* Figure out the max width and height */
 
259
    optimal_layout_width = H_PADDING;
 
260
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
261
        GtkRequisition requisition;
 
262
 
 
263
        button = p->data;
 
264
        gtk_widget_size_request (GTK_WIDGET (button->button_widget),
 
265
                                 &requisition);
 
266
        optimal_layout_width += requisition.width + H_PADDING;
 
267
        max_btn_height = MAX (max_btn_height, requisition.height);
 
268
        max_btn_width = MAX (max_btn_width, requisition.width);    
 
269
    }
 
270
 
 
271
    /* Figure out how many rows and columns we'll use. */
 
272
    btns_per_row = allocation->width / (max_btn_width + H_PADDING);
 
273
    
 
274
    /* If all the buttons could fit in the single row, have it so */
 
275
    if (allocation->width >= optimal_layout_width)
 
276
    {
 
277
        btns_per_row = num_btns;
 
278
    }
 
279
    if (!icons_only) {
 
280
        /* If using text buttons, we want to try to have a
 
281
         * completely filled-in grid, but if we can't, we want
 
282
         * the odd row to have just a single button.
 
283
         */
 
284
        while (num_btns % btns_per_row > 1)
 
285
            btns_per_row--;
 
286
    }
 
287
 
 
288
    rows_count = num_btns / btns_per_row;
 
289
    if (num_btns % btns_per_row != 0)
 
290
        rows_count++;
 
291
     
 
292
    /* Assign buttons to rows */
 
293
    rows = g_new0 (GSList *, rows_count);
 
294
 
 
295
    if (!icons_only && num_btns % btns_per_row != 0) {
 
296
        button = switcher->priv->buttons->data;
 
297
        rows [0] = g_slist_append (rows [0], button->button_widget);
 
298
 
 
299
        p = switcher->priv->buttons->next;
 
300
        row_number = p ? 1 : 0;
 
301
    } else {
 
302
        p = switcher->priv->buttons;
 
303
        row_number = 0;
 
304
    }
 
305
 
 
306
    for (; p != NULL; p = p->next) {
 
307
        button = p->data;
 
308
 
 
309
        if (g_slist_length (rows [row_number]) == btns_per_row)
 
310
            row_number ++;
 
311
 
 
312
        rows [row_number] = g_slist_append (rows [row_number],
 
313
                                            button->button_widget);
 
314
    }
 
315
 
 
316
    row_last = row_number;
 
317
 
 
318
    /* If there are more than 1 row of buttons, save the current height
 
319
     * requirement for subsequent size requests.
 
320
     */
 
321
    if (row_last > 0)
 
322
    {
 
323
        switcher->priv->buttons_height_request =
 
324
            (row_last + 1) * (max_btn_height + V_PADDING) + 1;
 
325
    } else { /* Otherwize clear it */
 
326
        if (last_buttons_height >= 0) {
 
327
 
 
328
            switcher->priv->buttons_height_request = -1;
 
329
        }
 
330
    }
 
331
    
 
332
    /* If it turns out that we now require smaller height for the buttons
 
333
     * than it was last time, make a resize request to ensure our
 
334
     * size requisition is properly communicated to the parent (otherwise
 
335
     * parent tend to keep assuming the older size).
 
336
     */
 
337
    if (last_buttons_height > switcher->priv->buttons_height_request)
 
338
    {
 
339
        gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
340
        return -1;
 
341
    }
 
342
    
 
343
    /* Layout the buttons. */
 
344
    for (i = row_last; i >= 0; i --) {
 
345
        int len, extra_width;
 
346
        
 
347
        y -= max_btn_height;
 
348
 
 
349
        /* Check for possible size over flow (taking into account client
 
350
         * requisition
 
351
         */
 
352
        if (y < (allocation->y + client_requisition.height)) {
 
353
            /* We have an overflow: Insufficient allocation */
 
354
            if (last_buttons_height < switcher->priv->buttons_height_request) {
 
355
                /* Request for a new resize */
 
356
                gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
357
                return -1;
 
358
            }
 
359
        }
 
360
        x = H_PADDING + allocation->x;
 
361
        len = g_slist_length (rows[i]);
 
362
        if (switcher_style == GDL_SWITCHER_STYLE_TEXT ||
 
363
            switcher_style == GDL_SWITCHER_STYLE_BOTH)
 
364
            extra_width = (allocation->width - (len * max_btn_width )
 
365
                           - (len * H_PADDING)) / len;
 
366
        else
 
367
            extra_width = 0;
 
368
        for (p = rows [i]; p != NULL; p = p->next) {
 
369
            GtkAllocation child_allocation;
 
370
            
 
371
            child_allocation.x = x;
 
372
            child_allocation.y = y;
 
373
            if (rows_count == 1 && row_number == 0)
 
374
            {
 
375
                GtkRequisition child_requisition;
 
376
                gtk_widget_size_request (GTK_WIDGET (p->data),
 
377
                                         &child_requisition);
 
378
                child_allocation.width = child_requisition.width;
 
379
            }
 
380
            else
 
381
            {
 
382
                child_allocation.width = max_btn_width + extra_width;
 
383
            }
 
384
            child_allocation.height = max_btn_height;
 
385
 
 
386
            gtk_widget_size_allocate (GTK_WIDGET (p->data), &child_allocation);
 
387
 
 
388
            x += child_allocation.width + H_PADDING;
 
389
        }
 
390
 
 
391
        y -= V_PADDING;
 
392
    }
 
393
    
 
394
    for (i = 0; i <= row_last; i ++)
 
395
        g_slist_free (rows [i]);
 
396
    g_free (rows);
 
397
 
 
398
    return y;
 
399
}
 
400
 
 
401
static void
 
402
do_layout (GdlSwitcher *switcher)
 
403
{
 
404
    GtkAllocation *allocation = & GTK_WIDGET (switcher)->allocation;
 
405
    GtkAllocation child_allocation;
 
406
    int y;
 
407
 
 
408
    if (switcher->priv->show) {
 
409
        y = layout_buttons (switcher);
 
410
        if (y < 0) /* Layout did not happen and a resize was requested */
 
411
            return;
 
412
    }
 
413
    else
 
414
        y = allocation->y + allocation->height;
 
415
    
 
416
    /* Place the parent widget.  */
 
417
    child_allocation.x = allocation->x;
 
418
    child_allocation.y = allocation->y;
 
419
    child_allocation.width = allocation->width;
 
420
    child_allocation.height = y - allocation->y;
 
421
    
 
422
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, size_allocate,
 
423
                     (GTK_WIDGET (switcher), &child_allocation));
 
424
}
 
425
 
 
426
/* GtkContainer methods.  */
 
427
 
 
428
static void
 
429
gdl_switcher_forall (GtkContainer *container, gboolean include_internals,
 
430
                     GtkCallback callback, void *callback_data)
 
431
{
 
432
    GdlSwitcher *switcher =
 
433
        GDL_SWITCHER (container);
 
434
    GSList *p;
 
435
    
 
436
    GDL_CALL_PARENT (GTK_CONTAINER_CLASS, forall,
 
437
                     (GTK_CONTAINER (switcher), include_internals,
 
438
                      callback, callback_data));
 
439
    if (include_internals) {
 
440
        for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
441
            GtkWidget *widget = ((Button *) p->data)->button_widget;
 
442
            (* callback) (widget, callback_data);
 
443
        }
 
444
    }
 
445
}
 
446
 
 
447
static void
 
448
gdl_switcher_remove (GtkContainer *container, GtkWidget *widget)
 
449
{
 
450
    gint switcher_id;
 
451
    GdlSwitcher *switcher =
 
452
        GDL_SWITCHER (container);
 
453
    GSList *p;
 
454
    
 
455
    switcher_id = gdl_switcher_get_page_id (widget);
 
456
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
457
        Button *b = (Button *) p->data;
 
458
 
 
459
        if (b->id == switcher_id) {
 
460
            gtk_widget_unparent (b->button_widget);
 
461
            switcher->priv->buttons =
 
462
                g_slist_remove_link (switcher->priv->buttons, p);
 
463
            button_free (b);
 
464
            gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
465
            break;
 
466
        }
 
467
    }
 
468
    GDL_CALL_PARENT (GTK_CONTAINER_CLASS, remove,
 
469
                     (GTK_CONTAINER (switcher), widget));
 
470
}
 
471
 
 
472
/* GtkWidget methods.  */
 
473
 
 
474
static void
 
475
gdl_switcher_size_request (GtkWidget *widget, GtkRequisition *requisition)
 
476
{
 
477
    GdlSwitcher *switcher = GDL_SWITCHER (widget);
 
478
    GSList *p;
 
479
    gint button_height = 0;
 
480
    
 
481
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, size_request,
 
482
                     (GTK_WIDGET (switcher), requisition));
 
483
 
 
484
    if (!switcher->priv->show)
 
485
        return;
 
486
    
 
487
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
488
        gint button_width;
 
489
        Button *button = p->data;
 
490
        GtkRequisition button_requisition;
 
491
 
 
492
        gtk_widget_size_request (button->button_widget, &button_requisition);
 
493
        button_width = button_requisition.width + 2 * H_PADDING;
 
494
        requisition->width = MAX (requisition->width, button_width);
 
495
        button_height = MAX (button_height,
 
496
                             button_requisition.height + 2 * V_PADDING);
 
497
    }
 
498
    
 
499
    if (switcher->priv->buttons_height_request > 0) {
 
500
        requisition->height += switcher->priv->buttons_height_request;
 
501
    } else {
 
502
        requisition->height += button_height + V_PADDING;
 
503
    }
 
504
}
 
505
 
 
506
static void
 
507
gdl_switcher_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
 
508
{
 
509
    widget->allocation = *allocation;
 
510
    do_layout (GDL_SWITCHER (widget));
 
511
}
 
512
 
 
513
static gint
 
514
gdl_switcher_expose (GtkWidget *widget, GdkEventExpose *event)
 
515
{
 
516
    GSList *p;
 
517
    GdlSwitcher *switcher = GDL_SWITCHER (widget);
 
518
    if (switcher->priv->show) {
 
519
        for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
520
            GtkWidget *button = ((Button *) p->data)->button_widget;
 
521
            gtk_container_propagate_expose (GTK_CONTAINER (widget),
 
522
                                            button, event);
 
523
        }
 
524
    }
 
525
    GDL_CALL_PARENT_WITH_DEFAULT (GTK_WIDGET_CLASS, expose_event,
 
526
                                  (widget, event), FALSE);
 
527
}
 
528
 
 
529
static void
 
530
gdl_switcher_map (GtkWidget *widget)
 
531
{
 
532
    GSList *p;
 
533
    GdlSwitcher *switcher = GDL_SWITCHER (widget);
 
534
    
 
535
    if (switcher->priv->show) {
 
536
        for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
537
            GtkWidget *button = ((Button *) p->data)->button_widget;
 
538
            gtk_widget_map (button);
 
539
        }
 
540
    }
 
541
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, map, (widget));
 
542
}
 
543
 
 
544
/* GObject methods.  */
 
545
 
 
546
static void
 
547
gdl_switcher_set_property  (GObject      *object,
 
548
                            guint         prop_id,
 
549
                            const GValue *value,
 
550
                            GParamSpec   *pspec)
 
551
{
 
552
    GdlSwitcher *switcher = GDL_SWITCHER (object);
 
553
 
 
554
    switch (prop_id) {
 
555
        case PROP_SWITCHER_STYLE:
 
556
            gdl_switcher_set_style (switcher, g_value_get_enum (value));
 
557
            break;
 
558
        default:
 
559
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
560
            break;
 
561
    }
 
562
}
 
563
 
 
564
static void
 
565
gdl_switcher_get_property  (GObject      *object,
 
566
                            guint         prop_id,
 
567
                            GValue       *value,
 
568
                            GParamSpec   *pspec)
 
569
{
 
570
    GdlSwitcher *switcher = GDL_SWITCHER (object);
 
571
 
 
572
    switch (prop_id) {
 
573
        case PROP_SWITCHER_STYLE:
 
574
            g_value_set_enum (value, gdl_switcher_get_style (switcher));
 
575
            break;
 
576
        default:
 
577
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
578
            break;
 
579
    }
 
580
}
 
581
 
 
582
static void
 
583
gdl_switcher_dispose (GObject *object)
 
584
{
 
585
    GdlSwitcherPrivate *priv = GDL_SWITCHER (object)->priv;
 
586
    
 
587
#if HAVE_GNOME
 
588
    GConfClient *gconf_client = gconf_client_get_default ();
 
589
    
 
590
    if (priv->style_changed_id) {
 
591
        gconf_client_notify_remove (gconf_client, priv->style_changed_id);
 
592
        priv->style_changed_id = 0;
 
593
    }
 
594
    g_object_unref (gconf_client);
 
595
#endif
 
596
    
 
597
    g_slist_foreach (priv->buttons, (GFunc) button_free, NULL);
 
598
    g_slist_free (priv->buttons);
 
599
    priv->buttons = NULL;
 
600
 
 
601
    GDL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
 
602
}
 
603
 
 
604
static void
 
605
gdl_switcher_finalize (GObject *object)
 
606
{
 
607
    GdlSwitcherPrivate *priv = GDL_SWITCHER (object)->priv;
 
608
 
 
609
    g_free (priv);
 
610
 
 
611
    GDL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
 
612
}
 
613
 
 
614
/* Signal handlers */
 
615
 
 
616
static void 
 
617
gdl_switcher_notify_cb (GObject *g_object, GParamSpec *pspec,
 
618
                        GdlSwitcher *switcher) 
 
619
{
 
620
    gboolean show_tabs;
 
621
    g_return_if_fail (switcher != NULL && GDL_IS_SWITCHER (switcher));
 
622
    show_tabs = gtk_notebook_get_show_tabs (GTK_NOTEBOOK (switcher));
 
623
    gdl_switcher_set_show_buttons (switcher, !show_tabs);
 
624
}
 
625
 
 
626
static void
 
627
gdl_switcher_switch_page_cb (GtkNotebook *nb, GtkNotebookPage *page,
 
628
                             gint page_num, GdlSwitcher *switcher)
 
629
{
 
630
    GtkWidget       *page_widget;
 
631
    GtkWidget       *tablabel;
 
632
    gint             switcher_id;
 
633
    
 
634
    /* Change switcher button */
 
635
    page_widget = gtk_notebook_get_nth_page (nb, page_num);
 
636
    switcher_id = gdl_switcher_get_page_id (page_widget);
 
637
    gdl_switcher_select_button (GDL_SWITCHER (switcher), switcher_id);
 
638
}
 
639
 
 
640
static void
 
641
gdl_switcher_page_added_cb (GtkNotebook *nb, GtkWidget *page,
 
642
                            gint page_num, GdlSwitcher *switcher)
 
643
{
 
644
    gint         switcher_id;
 
645
 
 
646
    switcher_id = gdl_switcher_get_page_id (page);
 
647
    
 
648
    gdl_switcher_add_button (GDL_SWITCHER (switcher), NULL, NULL, NULL, NULL,
 
649
                             switcher_id);
 
650
    gdl_switcher_select_button (GDL_SWITCHER (switcher), switcher_id);
 
651
}
 
652
 
 
653
static void
 
654
gdl_switcher_select_page (GdlSwitcher *switcher, gint id)
 
655
{
 
656
    GList *children, *node;
 
657
    children = gtk_container_get_children (GTK_CONTAINER (switcher));
 
658
    node = children;
 
659
    while (node)
 
660
    {
 
661
        gint switcher_id;
 
662
        switcher_id = gdl_switcher_get_page_id (GTK_WIDGET (node->data));
 
663
        if (switcher_id == id)
 
664
        {
 
665
            gint page_num;
 
666
            page_num = gtk_notebook_page_num (GTK_NOTEBOOK (switcher),
 
667
                                              GTK_WIDGET (node->data));
 
668
            g_signal_handlers_block_by_func (switcher,
 
669
                                             gdl_switcher_switch_page_cb,
 
670
                                             switcher);
 
671
            gtk_notebook_set_current_page (GTK_NOTEBOOK (switcher), page_num);
 
672
            g_signal_handlers_unblock_by_func (switcher,
 
673
                                               gdl_switcher_switch_page_cb,
 
674
                                               switcher);
 
675
            break;
 
676
        }
 
677
        node = g_list_next (node);
 
678
    }
 
679
    g_list_free (children);
 
680
}
 
681
 
 
682
/* Initialization.  */
 
683
 
 
684
static void
 
685
gdl_switcher_class_init (GdlSwitcherClass *klass)
 
686
{
 
687
    GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
 
688
    GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
 
689
    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
690
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
691
 
 
692
    container_class->forall = gdl_switcher_forall;
 
693
    container_class->remove = gdl_switcher_remove;
 
694
 
 
695
    widget_class->size_request = gdl_switcher_size_request;
 
696
    widget_class->size_allocate = gdl_switcher_size_allocate;
 
697
    widget_class->expose_event = gdl_switcher_expose;
 
698
    widget_class->map = gdl_switcher_map;
 
699
    
 
700
    object_class->dispose  = gdl_switcher_dispose;
 
701
    object_class->finalize = gdl_switcher_finalize;
 
702
    object_class->set_property = gdl_switcher_set_property;
 
703
    object_class->get_property = gdl_switcher_get_property;
 
704
    
 
705
    g_object_class_install_property (
 
706
        object_class, PROP_SWITCHER_STYLE,
 
707
        g_param_spec_enum ("switcher-style", _("Switcher Style"),
 
708
                           _("Switcher buttons style"),
 
709
                           GDL_TYPE_SWITCHER_STYLE,
 
710
                           GDL_SWITCHER_STYLE_BOTH,
 
711
                           G_PARAM_READWRITE));
 
712
}
 
713
 
 
714
static void
 
715
gdl_switcher_instance_init (GdlSwitcher *switcher)
 
716
{
 
717
    GdlSwitcherPrivate *priv;
 
718
 
 
719
    GTK_WIDGET_SET_FLAGS (switcher, GTK_NO_WINDOW);
 
720
  
 
721
    priv = g_new0 (GdlSwitcherPrivate, 1);
 
722
    switcher->priv = priv;
 
723
 
 
724
    priv->show = TRUE;
 
725
    priv->buttons_height_request = -1;
 
726
 
 
727
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (switcher), GTK_POS_BOTTOM);
 
728
    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (switcher), FALSE);
 
729
    gtk_notebook_set_show_border (GTK_NOTEBOOK (switcher), FALSE);
 
730
    gdl_switcher_set_style (switcher, GDL_SWITCHER_STYLE_BOTH);
 
731
    
 
732
    /* notebook signals */
 
733
    g_signal_connect (switcher, "switch-page",
 
734
                      G_CALLBACK (gdl_switcher_switch_page_cb), switcher);
 
735
    g_signal_connect (switcher, "page-added",
 
736
                      G_CALLBACK (gdl_switcher_page_added_cb), switcher);
 
737
    g_signal_connect (switcher, "notify::show-tabs",
 
738
                      G_CALLBACK (gdl_switcher_notify_cb), switcher);
 
739
}
 
740
 
 
741
GtkWidget *
 
742
gdl_switcher_new (void)
 
743
{
 
744
    GdlSwitcher *switcher = g_object_new (gdl_switcher_get_type (), NULL);
 
745
    return GTK_WIDGET (switcher);
 
746
}
 
747
 
 
748
void
 
749
gdl_switcher_add_button (GdlSwitcher *switcher, const gchar *label,
 
750
                         const gchar *tooltips, const gchar *stock_id,
 
751
                         const GdkPixbuf *pixbuf_icon, gint switcher_id)
 
752
{
 
753
    GtkWidget *button_widget;
 
754
    GtkWidget *hbox;
 
755
    GtkWidget *icon_widget;
 
756
    GtkWidget *label_widget;
 
757
    GtkWidget *arrow;
 
758
    GtkTooltips *button_tooltips;
 
759
    
 
760
    button_widget = gtk_toggle_button_new ();
 
761
    if (switcher->priv->show)
 
762
        gtk_widget_show (button_widget);
 
763
    g_signal_connect (button_widget, "toggled",
 
764
                      G_CALLBACK (button_toggled_callback),
 
765
                      switcher);
 
766
    hbox = gtk_hbox_new (FALSE, 3);
 
767
    gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
 
768
    gtk_container_add (GTK_CONTAINER (button_widget), hbox);
 
769
    gtk_widget_show (hbox);
 
770
 
 
771
    if (stock_id)
 
772
        icon_widget = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
 
773
    else if (pixbuf_icon)
 
774
        icon_widget = gtk_image_new_from_pixbuf (pixbuf_icon);
 
775
    else
 
776
        icon_widget = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_BUTTON);
 
777
 
 
778
    gtk_widget_show (icon_widget);
 
779
    
 
780
    if (!label) {
 
781
        gchar *text = g_strdup_printf ("Item %d", switcher_id);
 
782
        label_widget = gtk_label_new (text);
 
783
        g_free (text);
 
784
    } else {
 
785
        label_widget = gtk_label_new (label);
 
786
    }
 
787
    gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
 
788
    gtk_widget_show (label_widget);
 
789
    button_tooltips = gtk_tooltips_new();
 
790
    gtk_tooltips_set_tip (GTK_TOOLTIPS (button_tooltips), button_widget,
 
791
                          tooltips, NULL);        
 
792
 
 
793
    switch (INTERNAL_MODE (switcher)) {
 
794
    case GDL_SWITCHER_STYLE_TEXT:
 
795
        gtk_box_pack_start (GTK_BOX (hbox), label_widget, TRUE, TRUE, 0);
 
796
        gtk_tooltips_disable (button_tooltips);
 
797
        break;
 
798
    case GDL_SWITCHER_STYLE_ICON:
 
799
        gtk_box_pack_start (GTK_BOX (hbox), icon_widget, TRUE, TRUE, 0);
 
800
        gtk_tooltips_enable (button_tooltips);
 
801
        break;
 
802
    case GDL_SWITCHER_STYLE_BOTH:
 
803
    default:
 
804
        gtk_box_pack_start (GTK_BOX (hbox), icon_widget, FALSE, TRUE, 0);
 
805
        gtk_box_pack_start (GTK_BOX (hbox), label_widget, TRUE, TRUE, 0);
 
806
        gtk_tooltips_disable (button_tooltips);
 
807
        break;
 
808
    }
 
809
    arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_NONE);
 
810
    gtk_widget_show (arrow);
 
811
    gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
 
812
    
 
813
    switcher->priv->buttons =
 
814
        g_slist_append (switcher->priv->buttons,
 
815
                        button_new (button_widget, label_widget,
 
816
                                    icon_widget, button_tooltips,
 
817
                                    arrow, hbox, switcher_id));
 
818
    gtk_widget_set_parent (button_widget, GTK_WIDGET (switcher));
 
819
 
 
820
    gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
821
}
 
822
 
 
823
static void
 
824
gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id)
 
825
{
 
826
    GSList *p;
 
827
 
 
828
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
829
        Button *button = p->data;
 
830
 
 
831
        if (button->id == switcher_id)
 
832
        {
 
833
            gtk_container_remove (GTK_CONTAINER (switcher),
 
834
                                  button->button_widget);
 
835
            break;
 
836
        }            
 
837
    }
 
838
    gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
839
}
 
840
 
 
841
static void
 
842
gdl_switcher_select_button (GdlSwitcher *switcher, gint switcher_id)
 
843
{
 
844
    update_buttons (switcher, switcher_id);
 
845
    
 
846
    /* Select the notebook page associated with this button */
 
847
    gdl_switcher_select_page (switcher, switcher_id);
 
848
}
 
849
 
 
850
gint
 
851
gdl_switcher_insert_page (GdlSwitcher *switcher, GtkWidget *page,
 
852
                          GtkWidget *tab_widget, const gchar *label,
 
853
                          const gchar *tooltips, const gchar *stock_id,
 
854
                          const GdkPixbuf *pixbuf_icon, gint position)
 
855
{
 
856
    gint ret_position;
 
857
    gint switcher_id;
 
858
    g_signal_handlers_block_by_func (switcher,
 
859
                                     gdl_switcher_page_added_cb,
 
860
                                     switcher);
 
861
    
 
862
    if (!tab_widget) {
 
863
        tab_widget = gtk_label_new (label);
 
864
        gtk_widget_show (tab_widget);
 
865
    }
 
866
    switcher_id = gdl_switcher_get_page_id (page);
 
867
    gdl_switcher_add_button (switcher, label, tooltips, stock_id, pixbuf_icon, switcher_id);
 
868
    ret_position = gtk_notebook_insert_page (GTK_NOTEBOOK (switcher), page,
 
869
                                             tab_widget, position);
 
870
    g_signal_handlers_unblock_by_func (switcher,
 
871
                                       gdl_switcher_page_added_cb,
 
872
                                       switcher);
 
873
    return ret_position;
 
874
}
 
875
 
 
876
static void
 
877
set_switcher_style_internal (GdlSwitcher *switcher,
 
878
                             GdlSwitcherStyle switcher_style )
 
879
{
 
880
    GSList *p;
 
881
    
 
882
    if (switcher_style == GDL_SWITCHER_STYLE_TABS &&
 
883
        switcher->priv->show == FALSE)
 
884
        return;
 
885
 
 
886
    if (switcher_style == GDL_SWITCHER_STYLE_TABS)
 
887
    {
 
888
        gtk_notebook_set_show_tabs (GTK_NOTEBOOK (switcher), TRUE);
 
889
        return;
 
890
    }
 
891
    
 
892
    gtk_notebook_set_show_tabs (GTK_NOTEBOOK (switcher), FALSE);
 
893
    
 
894
    if (switcher_style == INTERNAL_MODE (switcher))
 
895
        return;
 
896
    
 
897
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
898
        Button *button = p->data;
 
899
 
 
900
        gtk_container_remove (GTK_CONTAINER (button->hbox), button->arrow);
 
901
        switch (switcher_style) {
 
902
        case GDL_SWITCHER_STYLE_TEXT:
 
903
            gtk_container_remove (GTK_CONTAINER (button->hbox), button->icon);
 
904
            if (INTERNAL_MODE (switcher)
 
905
                == GDL_SWITCHER_STYLE_ICON) {
 
906
                gtk_box_pack_start (GTK_BOX (button->hbox), button->label,
 
907
                                    TRUE, TRUE, 0);
 
908
                gtk_widget_show (button->label);
 
909
                gtk_tooltips_disable (button->tooltips);
 
910
            }
 
911
            break;
 
912
        case GDL_SWITCHER_STYLE_ICON:
 
913
            gtk_container_remove(GTK_CONTAINER (button->hbox), button->label);
 
914
            if (INTERNAL_MODE (switcher)
 
915
                == GDL_SWITCHER_STYLE_TEXT) {
 
916
                gtk_box_pack_start (GTK_BOX (button->hbox), button->icon,
 
917
                                    TRUE, TRUE, 0);
 
918
                gtk_widget_show (button->icon);
 
919
            } else
 
920
                gtk_container_child_set (GTK_CONTAINER (button->hbox),
 
921
                                         button->icon, "expand", TRUE, NULL);
 
922
            gtk_tooltips_enable (button->tooltips);
 
923
            break;
 
924
        case GDL_SWITCHER_STYLE_BOTH:
 
925
            if (INTERNAL_MODE (switcher)
 
926
                == GDL_SWITCHER_STYLE_TEXT) {
 
927
                gtk_container_remove (GTK_CONTAINER (button->hbox),
 
928
                                      button->label);
 
929
                gtk_box_pack_start (GTK_BOX (button->hbox), button->icon,
 
930
                                    FALSE, TRUE, 0);
 
931
                gtk_widget_show (button->icon);
 
932
            } else {
 
933
                gtk_container_child_set (GTK_CONTAINER (button->hbox),
 
934
                                         button->icon, "expand", FALSE, NULL);
 
935
            }
 
936
 
 
937
            gtk_tooltips_disable (button->tooltips);
 
938
            gtk_box_pack_start (GTK_BOX (button->hbox), button->label, TRUE,
 
939
                                TRUE, 0);
 
940
            gtk_widget_show (button->label);
 
941
            break;
 
942
        default:
 
943
            break;
 
944
        }
 
945
        gtk_box_pack_start (GTK_BOX (button->hbox), button->arrow, FALSE,
 
946
                            FALSE, 0);
 
947
    }
 
948
}
 
949
 
 
950
#if HAVE_GNOME
 
951
static GConfEnumStringPair toolbar_styles[] = {
 
952
    { GDL_SWITCHER_STYLE_TEXT, "text" },
 
953
    { GDL_SWITCHER_STYLE_ICON, "icons" },
 
954
    { GDL_SWITCHER_STYLE_BOTH, "both" },
 
955
    { GDL_SWITCHER_STYLE_BOTH, "both-horiz" },
 
956
    { GDL_SWITCHER_STYLE_BOTH, "both_horiz" },
 
957
    { -1, NULL }
 
958
};
 
959
 
 
960
static void
 
961
style_changed_notify (GConfClient *gconf, guint id, GConfEntry *entry,
 
962
                      void *data)
 
963
{
 
964
    GdlSwitcher *switcher = data;
 
965
    char *val;
 
966
    int switcher_style;    
 
967
    
 
968
    val = gconf_client_get_string (gconf,
 
969
                                   "/desktop/gnome/interface/toolbar_style",
 
970
                                   NULL);
 
971
    if (val == NULL || !gconf_string_to_enum (toolbar_styles, val,
 
972
                                              &switcher_style))
 
973
        switcher_style = GDL_SWITCHER_STYLE_BOTH;
 
974
    g_free(val);
 
975
 
 
976
    set_switcher_style_internal (GDL_SWITCHER (switcher), switcher_style);
 
977
    switcher->priv->toolbar_style = switcher_style;
 
978
 
 
979
    gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
980
}
 
981
 
 
982
static void
 
983
gdl_switcher_set_style (GdlSwitcher *switcher, GdlSwitcherStyle switcher_style)
 
984
{
 
985
    GConfClient *gconf_client = gconf_client_get_default ();
 
986
    
 
987
    if (switcher_style == GDL_SWITCHER_STYLE_TABS &&
 
988
        switcher->priv->show == FALSE)
 
989
        return;
 
990
    
 
991
    if (switcher->priv->switcher_style == switcher_style &&
 
992
        switcher->priv->show == TRUE)
 
993
        return;
 
994
 
 
995
    if (switcher->priv->switcher_style == GDL_SWITCHER_STYLE_TOOLBAR) {
 
996
        if (switcher->priv->style_changed_id) {
 
997
            gconf_client_notify_remove (gconf_client,
 
998
                                switcher->priv->style_changed_id);
 
999
            switcher->priv->style_changed_id = 0;
 
1000
        }        
 
1001
    }
 
1002
    
 
1003
    if (switcher_style != GDL_SWITCHER_STYLE_TOOLBAR) {
 
1004
        set_switcher_style_internal (switcher, switcher_style);
 
1005
 
 
1006
        gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
1007
    } else {
 
1008
        /* This is a little bit tricky, toolbar style is more
 
1009
         * of a meta-style where the actual style is dictated by
 
1010
         * the gnome toolbar setting, so that is why we have
 
1011
         * the is_toolbar_style bool - it tracks the toolbar
 
1012
         * style while the switcher_style member is the actual look and
 
1013
         * feel */
 
1014
        switcher->priv->style_changed_id =
 
1015
            gconf_client_notify_add (gconf_client,
 
1016
                                     "/desktop/gnome/interface/toolbar_style",
 
1017
                                     style_changed_notify, switcher,
 
1018
                                     NULL, NULL);
 
1019
        style_changed_notify (gconf_client, 0, NULL, switcher);
 
1020
    }
 
1021
    
 
1022
    g_object_unref (gconf_client);
 
1023
 
 
1024
    if (switcher_style != GDL_SWITCHER_STYLE_TABS)
 
1025
        switcher->priv->switcher_style = switcher_style;
 
1026
}
 
1027
 
 
1028
#else /* HAVE_GNOME */
 
1029
 
 
1030
static void
 
1031
gdl_switcher_set_style (GdlSwitcher *switcher, GdlSwitcherStyle switcher_style)
 
1032
{
 
1033
    if (switcher_style == GDL_SWITCHER_STYLE_TABS &&
 
1034
        switcher->priv->show == FALSE)
 
1035
        return;
 
1036
    
 
1037
    if (switcher->priv->switcher_style == switcher_style &&
 
1038
        switcher->priv->show == TRUE)
 
1039
        return;
 
1040
 
 
1041
    set_switcher_style_internal (switcher,
 
1042
                                 ((switcher_style ==
 
1043
                                   GDL_SWITCHER_STYLE_TOOLBAR)?
 
1044
                                  GDL_SWITCHER_STYLE_BOTH : switcher_style));
 
1045
    gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
1046
    
 
1047
    if (switcher_style != GDL_SWITCHER_STYLE_TABS)
 
1048
        switcher->priv->switcher_style = switcher_style;
 
1049
}
 
1050
 
 
1051
#endif /* HAVE_GNOME */
 
1052
 
 
1053
static void
 
1054
gdl_switcher_set_show_buttons (GdlSwitcher *switcher, gboolean show)
 
1055
{
 
1056
    GSList *p;
 
1057
 
 
1058
    if (switcher->priv->show == show)
 
1059
        return;
 
1060
    
 
1061
    for (p = switcher->priv->buttons; p != NULL; p = p->next) {
 
1062
        Button *button = p->data;
 
1063
 
 
1064
        if (show)
 
1065
            gtk_widget_show (button->button_widget);
 
1066
        else
 
1067
            gtk_widget_hide (button->button_widget);
 
1068
    }
 
1069
 
 
1070
    switcher->priv->show = show;
 
1071
 
 
1072
    gtk_widget_queue_resize (GTK_WIDGET (switcher));
 
1073
}
 
1074
 
 
1075
static GdlSwitcherStyle
 
1076
gdl_switcher_get_style (GdlSwitcher *switcher)
 
1077
{
 
1078
    if (!switcher->priv->show)
 
1079
        return GDL_SWITCHER_STYLE_TABS;
 
1080
    return switcher->priv->switcher_style;
 
1081
}