]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolbar.c
Demo works fine. I have to add the missing functions for setting the toolbar's
[~andy/gtk] / gtk / gtktoolbar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * GtkToolbar copyright (C) Federico Mena
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include "gtkbutton.h"
21 #include "gtklabel.h"
22 #include "gtkvbox.h"
23 #include "gtktoolbar.h"
24
25
26 #define DEFAULT_SPACE_SIZE 5
27
28
29 typedef struct {
30         GtkWidget *button;
31         GtkWidget *icon;
32         GtkWidget *label;
33 } Child;
34
35
36 static void gtk_toolbar_class_init    (GtkToolbarClass *class);
37 static void gtk_toolbar_init          (GtkToolbar      *toolbar);
38 static void gtk_toolbar_destroy       (GtkObject       *object);
39 static void gtk_toolbar_map           (GtkWidget       *widget);
40 static void gtk_toolbar_unmap         (GtkWidget       *widget);
41 static void gtk_toolbar_draw          (GtkWidget       *widget,
42                                        GdkRectangle    *area);
43 static void gtk_toolbar_size_request  (GtkWidget       *widget,
44                                        GtkRequisition  *requisition);
45 static void gtk_toolbar_size_allocate (GtkWidget       *widget,
46                                        GtkAllocation   *allocation);
47 static void gtk_toolbar_add           (GtkContainer    *container,
48                                        GtkWidget       *widget);
49 static void gtk_toolbar_foreach       (GtkContainer    *container,
50                                        GtkCallback      callback,
51                                        gpointer         callback_data);
52
53 static GtkContainerClass *parent_class;
54
55
56 guint
57 gtk_toolbar_get_type(void)
58 {
59         static guint toolbar_type = 0;
60
61         if (!toolbar_type) {
62                 GtkTypeInfo toolbar_info = {
63                         "GtkToolbar",
64                         sizeof(GtkToolbar),
65                         sizeof(GtkToolbarClass),
66                         (GtkClassInitFunc) gtk_toolbar_class_init,
67                         (GtkObjectInitFunc) gtk_toolbar_init,
68                         (GtkArgFunc) NULL
69                 };
70
71                 toolbar_type = gtk_type_unique(gtk_container_get_type(), &toolbar_info);
72         }
73
74         return toolbar_type;
75 }
76
77 static void
78 gtk_toolbar_class_init(GtkToolbarClass *class)
79 {
80         GtkObjectClass *object_class;
81         GtkWidgetClass *widget_class;
82         GtkContainerClass *container_class;
83
84         object_class = (GtkObjectClass *) class;
85         widget_class = (GtkWidgetClass *) class;
86         container_class = (GtkContainerClass *) class;
87
88         parent_class = gtk_type_class(gtk_container_get_type());
89
90         object_class->destroy = gtk_toolbar_destroy;
91
92         widget_class->map = gtk_toolbar_map;
93         widget_class->unmap = gtk_toolbar_unmap;
94         widget_class->draw = gtk_toolbar_draw;
95         widget_class->size_request = gtk_toolbar_size_request;
96         widget_class->size_allocate = gtk_toolbar_size_allocate;
97
98         container_class->add = gtk_toolbar_add;
99         container_class->foreach = gtk_toolbar_foreach;
100 }
101
102 static void
103 gtk_toolbar_init(GtkToolbar *toolbar)
104 {
105         GTK_WIDGET_SET_FLAGS(toolbar, GTK_NO_WINDOW);
106
107         toolbar->num_children = 0;
108         toolbar->children     = NULL;
109         toolbar->orientation  = GTK_ORIENTATION_HORIZONTAL;
110         toolbar->style        = GTK_TOOLBAR_ICONS;
111         toolbar->space_size   = DEFAULT_SPACE_SIZE;
112         toolbar->tooltips     = gtk_tooltips_new();
113 }
114
115 GtkWidget *
116 gtk_toolbar_new(GtkOrientation  orientation,
117                 GtkToolbarStyle style)
118 {
119         GtkToolbar *toolbar;
120
121         toolbar = gtk_type_new(gtk_toolbar_get_type());
122
123         toolbar->orientation = orientation;
124         toolbar->style = style;
125
126         return GTK_WIDGET(toolbar);
127 }
128
129
130 static void
131 gtk_toolbar_destroy(GtkObject *object)
132 {
133         GtkToolbar *toolbar;
134         GList      *children;
135         Child      *child;
136
137         g_return_if_fail(object != NULL);
138         g_return_if_fail(GTK_IS_TOOLBAR(object));
139
140         toolbar = GTK_TOOLBAR(object);
141
142         gtk_tooltips_unref(toolbar->tooltips); /* XXX: do I have to unref the tooltips? */
143
144         for (children = toolbar->children; children; children = children->next) {
145                 child = children->data;
146
147                 /* NULL child means it is a space in the toolbar, rather than a button */
148                 if (child) {
149                         child->button->parent = NULL;
150                         gtk_object_unref(GTK_OBJECT(child->button));
151                         gtk_widget_destroy(child->button);
152                         g_free(child);
153                 }
154         }
155
156         g_list_free(toolbar->children);
157
158         if (GTK_OBJECT_CLASS(parent_class)->destroy)
159                 (* GTK_OBJECT_CLASS(parent_class)->destroy) (object);
160 }
161
162 static void
163 gtk_toolbar_map(GtkWidget *widget)
164 {
165         GtkToolbar *toolbar;
166         GList      *children;
167         Child      *child;
168
169         g_return_if_fail(widget != NULL);
170         g_return_if_fail(GTK_IS_TOOLBAR(widget));
171
172         toolbar = GTK_TOOLBAR(widget);
173         GTK_WIDGET_SET_FLAGS(toolbar, GTK_MAPPED);
174
175         for (children = toolbar->children; children; children = children->next) {
176                 child = children->data;
177
178                 if (child && GTK_WIDGET_VISIBLE(child->button) && !GTK_WIDGET_MAPPED(child->button))
179                         gtk_widget_map(child->button);
180         }
181 }
182
183 static void
184 gtk_toolbar_unmap(GtkWidget *widget)
185 {
186         GtkToolbar *toolbar;
187         GList      *children;
188         Child      *child;
189
190         g_return_if_fail(widget != NULL);
191         g_return_if_fail(GTK_IS_TOOLBAR(widget));
192         
193         toolbar = GTK_TOOLBAR(widget);
194         GTK_WIDGET_UNSET_FLAGS(toolbar, GTK_MAPPED);
195
196         for (children = toolbar->children; children; children = children->next) {
197                 child = children->data;
198
199                 if (child && GTK_WIDGET_VISIBLE(child->button) && GTK_WIDGET_MAPPED(child->button))
200                         gtk_widget_unmap(child->button);
201         }
202 }
203
204 static void
205 gtk_toolbar_draw(GtkWidget    *widget,
206                  GdkRectangle *area)
207 {
208         GtkToolbar   *toolbar;
209         GList        *children;
210         Child        *child;
211         GdkRectangle  child_area;
212
213         g_return_if_fail(widget != NULL);
214         g_return_if_fail(GTK_IS_TOOLBAR(widget));
215
216         if (GTK_WIDGET_DRAWABLE(widget)) {
217                 toolbar = GTK_TOOLBAR(widget);
218
219                 for (children = toolbar->children; children; children = children->next) {
220                         child = children->data;
221
222                         if (child && gtk_widget_intersect(child->button, area, &child_area))
223                                 gtk_widget_draw(child->button, &child_area);
224                 }
225         }
226 }
227
228 static void
229 gtk_toolbar_size_request(GtkWidget      *widget,
230                          GtkRequisition *requisition)
231 {
232         GtkToolbar     *toolbar;
233         GList          *children;
234         Child          *child;
235         gint            nchildren;
236
237         g_return_if_fail(widget != NULL);
238         g_return_if_fail(GTK_IS_TOOLBAR(widget));
239         g_return_if_fail(requisition != NULL);
240
241         toolbar = GTK_TOOLBAR(widget);
242
243         requisition->width = GTK_CONTAINER(toolbar)->border_width * 2;
244         requisition->height = GTK_CONTAINER(toolbar)->border_width * 2;
245         nchildren = 0;
246         toolbar->child_maxw = 0;
247         toolbar->child_maxh = 0;
248
249         for (children = toolbar->children; children; children = children->next) {
250                 child = children->data;
251
252                 if (child) {
253                         nchildren++;
254
255                         gtk_widget_size_request(child->button, &child->button->requisition);
256
257                         toolbar->child_maxw = MAX(toolbar->child_maxw, child->button->requisition.width);
258                         toolbar->child_maxh = MAX(toolbar->child_maxh, child->button->requisition.height);
259                 } else
260                         /* NULL child means it is a space in the toolbar, rather than a button */
261                         if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
262                                 requisition->width += toolbar->space_size;
263                         else
264                                 requisition->height += toolbar->space_size;
265         }
266
267         if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) {
268                 requisition->width += nchildren * toolbar->child_maxw;
269                 requisition->height += toolbar->child_maxh;
270         } else {
271                 requisition->width += toolbar->child_maxw;
272                 requisition->height += nchildren * toolbar->child_maxh;
273         }
274 }
275
276 static void
277 gtk_toolbar_size_allocate(GtkWidget     *widget,
278                           GtkAllocation *allocation)
279 {
280         GtkToolbar     *toolbar;
281         GList          *children;
282         Child          *child;
283         GtkAllocation   alloc;
284
285         g_return_if_fail(widget != NULL);
286         g_return_if_fail(GTK_IS_TOOLBAR(widget));
287         g_return_if_fail(allocation != NULL);
288
289         toolbar = GTK_TOOLBAR(widget);
290         widget->allocation = *allocation;
291
292         alloc.x      = allocation->x + GTK_CONTAINER(toolbar)->border_width;
293         alloc.y      = allocation->y + GTK_CONTAINER(toolbar)->border_width;
294         alloc.width  = toolbar->child_maxw;
295         alloc.height = toolbar->child_maxh;
296
297         for (children = toolbar->children; children; children = children->next) {
298                 child = children->data;
299
300                 if (child) {
301                         gtk_widget_size_allocate(child->button, &alloc);
302
303                         if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
304                                 alloc.x += toolbar->child_maxw;
305                         else
306                                 alloc.y += toolbar->child_maxh;
307                 } else
308                         /* NULL child means it is a space in the toolbar, rather than a button */
309                         if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL)
310                                 alloc.x += toolbar->space_size;
311                         else
312                                 alloc.y += toolbar->space_size;
313         }
314 }
315
316 static void
317 gtk_toolbar_add(GtkContainer *container,
318                 GtkWidget    *widget)
319 {
320         g_warning("gtk_toolbar_add: use gtk_toolbar_add_item() instead!");
321 }
322
323 static void
324 gtk_toolbar_foreach(GtkContainer    *container,
325                     GtkCallback      callback,
326                     gpointer         callback_data)
327 {
328         GtkToolbar *toolbar;
329         GList      *children;
330         Child      *child;
331
332         g_return_if_fail(container != NULL);
333         g_return_if_fail(GTK_IS_TOOLBAR(container));
334         g_return_if_fail(callback != NULL);
335
336         toolbar = GTK_TOOLBAR(container);
337
338         for (children = toolbar->children; children; children = children->next) {
339                 child = children->data;
340
341                 if (child)
342                         (*callback) (child->button, callback_data);
343         }
344 }
345
346 void
347 gtk_toolbar_append_item(GtkToolbar      *toolbar,
348                         const char      *text,
349                         const char      *tooltip_text,
350                         GtkPixmap       *icon,
351                         GtkSignalFunc    callback,
352                         gpointer         user_data)
353 {
354         gtk_toolbar_insert_item(toolbar, text, tooltip_text, icon,
355                                 callback, user_data, toolbar->num_children);
356 }
357
358 void
359 gtk_toolbar_prepend_item(GtkToolbar      *toolbar,
360                          const char      *text,
361                          const char      *tooltip_text,
362                          GtkPixmap       *icon,
363                          GtkSignalFunc    callback,
364                          gpointer         user_data)
365 {
366         gtk_toolbar_insert_item(toolbar, text, tooltip_text, icon,
367                                 callback, user_data, 0);
368 }
369
370 void
371 gtk_toolbar_insert_item(GtkToolbar      *toolbar,
372                         const char      *text,
373                         const char      *tooltip_text,
374                         GtkPixmap       *icon,
375                         GtkSignalFunc    callback,
376                         gpointer         user_data,
377                         gint             position)
378 {
379         Child     *child;
380         GtkWidget *vbox;
381
382         g_return_if_fail(toolbar != NULL);
383         g_return_if_fail(GTK_IS_TOOLBAR(toolbar));
384
385         child = g_new(Child, 1);
386
387         child->button = gtk_button_new();
388
389         if (callback)
390                 gtk_signal_connect(GTK_OBJECT(child->button), "clicked",
391                                    callback, user_data);
392
393         if (text)
394                 child->label = gtk_label_new(text);
395         else
396                 child->label = NULL;
397         
398         child->icon = GTK_WIDGET(icon);
399
400         vbox = gtk_vbox_new(FALSE, 0);
401         gtk_container_add(GTK_CONTAINER(child->button), vbox);
402         gtk_widget_show(vbox);
403
404         if (child->icon)
405                 gtk_box_pack_start(GTK_BOX(vbox), child->icon, FALSE, FALSE, 0);
406
407         if (child->label)
408                 gtk_box_pack_start(GTK_BOX(vbox), child->label, FALSE, FALSE, 0);
409
410         switch (toolbar->style) {
411                 case GTK_TOOLBAR_ICONS:
412                         if (child->icon)
413                                 gtk_widget_show(child->icon);
414                         break;
415
416                 case GTK_TOOLBAR_TEXT:
417                         if (child->label)
418                                 gtk_widget_show(child->label);
419                         break;
420
421                 case GTK_TOOLBAR_BOTH:
422                         if (child->icon)
423                                 gtk_widget_show(child->icon);
424
425                         if (child->label)
426                                 gtk_widget_show(child->label);
427
428                         break;
429
430                 default:
431                         g_assert_not_reached();
432         }
433
434         gtk_widget_show(child->button);
435
436         toolbar->children = g_list_insert(toolbar->children, child, position);
437         toolbar->num_children++;
438
439         gtk_widget_set_parent(child->button, GTK_WIDGET(toolbar));
440
441         if (GTK_WIDGET_VISIBLE(toolbar)) {
442                 if (GTK_WIDGET_REALIZED(toolbar)
443                     && !GTK_WIDGET_REALIZED(child->button))
444                         gtk_widget_realize(child->button);
445
446                 if (GTK_WIDGET_MAPPED(toolbar)
447                     && !GTK_WIDGET_MAPPED(child->button))
448                         gtk_widget_map(child->button);
449         }
450
451         if (GTK_WIDGET_VISIBLE(child->button) && GTK_WIDGET_VISIBLE(toolbar))
452                 gtk_widget_queue_resize(child->button);
453 }
454
455 void
456 gtk_toolbar_append_space(GtkToolbar *toolbar)
457 {
458         gtk_toolbar_insert_space(toolbar, toolbar->num_children);
459 }
460
461 void
462 gtk_toolbar_prepend_space(GtkToolbar *toolbar)
463 {
464         gtk_toolbar_insert_space(toolbar, 0);
465 }
466
467 void
468 gtk_toolbar_insert_space(GtkToolbar *toolbar,
469                          gint        position)
470 {
471         g_return_if_fail(toolbar != NULL);
472         g_return_if_fail(GTK_IS_TOOLBAR(toolbar));
473
474         /* NULL child means it is a space in the toolbar, rather than a button */
475
476         toolbar->children = g_list_insert(toolbar->children, NULL, position);
477         toolbar->num_children++;
478
479         if (GTK_WIDGET_VISIBLE(toolbar))
480                 gtk_widget_queue_resize(GTK_WIDGET(toolbar));
481 }