]> Pileus Git - ~andy/gtk/blob - gtk/gtkmenubar.c
Merge from themes-2. See the ChangeLog for a somewhat detailed
[~andy/gtk] / gtk / gtkmenubar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include "gdk/gdkkeysyms.h"
20 #include "gtkbindings.h"
21 #include "gtkmain.h"
22 #include "gtkmenubar.h"
23 #include "gtkmenuitem.h"
24
25
26 #define BORDER_SPACING  2
27 #define CHILD_SPACING   3
28
29
30 static void gtk_menu_bar_class_init    (GtkMenuBarClass *klass);
31 static void gtk_menu_bar_init          (GtkMenuBar      *menu_bar);
32 static void gtk_menu_bar_size_request  (GtkWidget       *widget,
33                                         GtkRequisition  *requisition);
34 static void gtk_menu_bar_size_allocate (GtkWidget       *widget,
35                                         GtkAllocation   *allocation);
36 static void gtk_menu_bar_paint         (GtkWidget       *widget,
37                                         GdkRectangle    *area);
38 static void gtk_menu_bar_draw          (GtkWidget       *widget,
39                                         GdkRectangle    *area);
40 static gint gtk_menu_bar_expose        (GtkWidget       *widget,
41                                         GdkEventExpose  *event);
42
43
44 GtkType
45 gtk_menu_bar_get_type (void)
46 {
47   static GtkType menu_bar_type = 0;
48
49   if (!menu_bar_type)
50     {
51       GtkTypeInfo menu_bar_info =
52       {
53         "GtkMenuBar",
54         sizeof (GtkMenuBar),
55         sizeof (GtkMenuBarClass),
56         (GtkClassInitFunc) gtk_menu_bar_class_init,
57         (GtkObjectInitFunc) gtk_menu_bar_init,
58         /* reserved_1 */ NULL,
59         /* reserved_2 */ NULL,
60         (GtkClassInitFunc) NULL,
61       };
62
63       menu_bar_type = gtk_type_unique (gtk_menu_shell_get_type (), &menu_bar_info);
64     }
65
66   return menu_bar_type;
67 }
68
69 static void
70 gtk_menu_bar_class_init (GtkMenuBarClass *class)
71 {
72   GtkWidgetClass *widget_class;
73   GtkMenuShellClass *menu_shell_class;
74
75   GtkBindingSet *binding_set;
76
77   widget_class = (GtkWidgetClass*) class;
78   menu_shell_class = (GtkMenuShellClass*) class;
79
80   widget_class->draw = gtk_menu_bar_draw;
81   widget_class->size_request = gtk_menu_bar_size_request;
82   widget_class->size_allocate = gtk_menu_bar_size_allocate;
83   widget_class->expose_event = gtk_menu_bar_expose;
84
85   menu_shell_class->submenu_placement = GTK_TOP_BOTTOM;
86
87   binding_set = gtk_binding_set_by_class (class);
88   gtk_binding_entry_add_signal (binding_set,
89                                 GDK_Left, 0,
90                                 "move_current", 1,
91                                 GTK_TYPE_MENU_DIRECTION_TYPE,
92                                 GTK_MENU_DIR_PREV);
93   gtk_binding_entry_add_signal (binding_set,
94                                 GDK_Right, 0,
95                                 "move_current", 1,
96                                 GTK_TYPE_MENU_DIRECTION_TYPE,
97                                 GTK_MENU_DIR_NEXT);
98   gtk_binding_entry_add_signal (binding_set,
99                                 GDK_Up, 0,
100                                 "move_current", 1,
101                                 GTK_TYPE_MENU_DIRECTION_TYPE,
102                                 GTK_MENU_DIR_PARENT);
103   gtk_binding_entry_add_signal (binding_set,
104                                 GDK_Down, 0,
105                                 "move_current", 1,
106                                 GTK_TYPE_MENU_DIRECTION_TYPE,
107                                 GTK_MENU_DIR_CHILD);
108 }
109
110 static void
111 gtk_menu_bar_init (GtkMenuBar *menu_bar)
112 {
113 }
114
115 GtkWidget*
116 gtk_menu_bar_new (void)
117 {
118   return GTK_WIDGET (gtk_type_new (gtk_menu_bar_get_type ()));
119 }
120
121 void
122 gtk_menu_bar_append (GtkMenuBar *menu_bar,
123                      GtkWidget  *child)
124 {
125   gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), child);
126 }
127
128 void
129 gtk_menu_bar_prepend (GtkMenuBar *menu_bar,
130                       GtkWidget  *child)
131 {
132   gtk_menu_shell_prepend (GTK_MENU_SHELL (menu_bar), child);
133 }
134
135 void
136 gtk_menu_bar_insert (GtkMenuBar *menu_bar,
137                      GtkWidget  *child,
138                      gint        position)
139 {
140   gtk_menu_shell_insert (GTK_MENU_SHELL (menu_bar), child, position);
141 }
142
143
144 static void
145 gtk_menu_bar_size_request (GtkWidget      *widget,
146                            GtkRequisition *requisition)
147 {
148   GtkMenuBar *menu_bar;
149   GtkMenuShell *menu_shell;
150   GtkWidget *child;
151   GList *children;
152   gint nchildren;
153
154   g_return_if_fail (widget != NULL);
155   g_return_if_fail (GTK_IS_MENU_BAR (widget));
156   g_return_if_fail (requisition != NULL);
157
158   requisition->width = 0;
159   requisition->height = 0;
160
161   if (GTK_WIDGET_VISIBLE (widget))
162     {
163       menu_bar = GTK_MENU_BAR (widget);
164       menu_shell = GTK_MENU_SHELL (widget);
165
166       nchildren = 0;
167       children = menu_shell->children;
168
169       while (children)
170         {
171           child = children->data;
172           children = children->next;
173
174           if (GTK_WIDGET_VISIBLE (child))
175             {
176               GTK_MENU_ITEM (child)->show_submenu_indicator = FALSE;
177               gtk_widget_size_request (child, &child->requisition);
178
179               requisition->width += child->requisition.width;
180               requisition->height = MAX (requisition->height, child->requisition.height);
181               /* Support for the right justified help menu */
182               if ( (children == NULL) && (GTK_IS_MENU_ITEM(child))
183                    && (GTK_MENU_ITEM(child)->right_justify))
184                 {
185                   requisition->width += CHILD_SPACING;
186                 }
187
188               nchildren += 1;
189             }
190         }
191
192       requisition->width += (GTK_CONTAINER (menu_bar)->border_width +
193                              widget->style->klass->xthickness +
194                              BORDER_SPACING) * 2;
195       requisition->height += (GTK_CONTAINER (menu_bar)->border_width +
196                               widget->style->klass->ythickness +
197                               BORDER_SPACING) * 2;
198
199       if (nchildren > 0)
200         requisition->width += 2 * CHILD_SPACING * (nchildren - 1);
201     }
202 }
203
204 static void
205 gtk_menu_bar_size_allocate (GtkWidget     *widget,
206                             GtkAllocation *allocation)
207 {
208   GtkMenuBar *menu_bar;
209   GtkMenuShell *menu_shell;
210   GtkWidget *child;
211   GList *children;
212   GtkAllocation child_allocation;
213   guint offset;
214   
215   g_return_if_fail (widget != NULL);
216   g_return_if_fail (GTK_IS_MENU_BAR (widget));
217   g_return_if_fail (allocation != NULL);
218
219   menu_bar = GTK_MENU_BAR (widget);
220   menu_shell = GTK_MENU_SHELL (widget);
221
222   widget->allocation = *allocation;
223   if (GTK_WIDGET_REALIZED (widget))
224     gdk_window_move_resize (widget->window,
225                             allocation->x, allocation->y,
226                             allocation->width, allocation->height);
227
228   if (menu_shell->children)
229     {
230       child_allocation.x = (GTK_CONTAINER (menu_bar)->border_width +
231                             widget->style->klass->xthickness +
232                             BORDER_SPACING);
233       offset = child_allocation.x;      /* Window edge to menubar start */
234
235       child_allocation.y = (GTK_CONTAINER (menu_bar)->border_width +
236                             widget->style->klass->ythickness +
237                             BORDER_SPACING);
238       child_allocation.height = MAX (1, allocation->height - child_allocation.y * 2);
239
240       children = menu_shell->children;
241       while (children)
242         {
243           child = children->data;
244           children = children->next;
245
246           /* Support for the right justified help menu */
247           if ( (children == NULL) && (GTK_IS_MENU_ITEM(child))
248               && (GTK_MENU_ITEM(child)->right_justify)) 
249             {
250               child_allocation.x = allocation->width -
251                   child->requisition.width - CHILD_SPACING - offset;
252             }
253           if (GTK_WIDGET_VISIBLE (child))
254             {
255               child_allocation.width = child->requisition.width;
256
257               gtk_widget_size_allocate (child, &child_allocation);
258
259               child_allocation.x += child_allocation.width + CHILD_SPACING * 2;
260             }
261         }
262     }
263 }
264
265 static void
266 gtk_menu_bar_paint (GtkWidget *widget, GdkRectangle *area)
267 {
268   g_return_if_fail (widget != NULL);
269   g_return_if_fail (GTK_IS_MENU_BAR (widget));
270
271   if (GTK_WIDGET_DRAWABLE (widget))
272     {
273       gtk_paint_box (widget->style,
274                      widget->window,
275                      GTK_STATE_NORMAL,
276                      GTK_SHADOW_OUT,
277                      area, widget, "menubar",
278                      0, 0,
279                      -1,-1);
280     }
281 }
282
283 static void
284 gtk_menu_bar_draw (GtkWidget    *widget,
285                    GdkRectangle *area)
286 {
287   GtkMenuShell *menu_shell;
288   GtkWidget *child;
289   GdkRectangle child_area;
290   GList *children;
291
292   g_return_if_fail (widget != NULL);
293   g_return_if_fail (GTK_IS_MENU_BAR (widget));
294   g_return_if_fail (area != NULL);
295
296   if (GTK_WIDGET_DRAWABLE (widget))
297     {
298       gtk_menu_bar_paint (widget, area);
299
300       menu_shell = GTK_MENU_SHELL (widget);
301
302       children = menu_shell->children;
303       while (children)
304         {
305           child = children->data;
306           children = children->next;
307
308           if (gtk_widget_intersect (child, area, &child_area))
309             gtk_widget_draw (child, &child_area);
310         }
311     }
312 }
313
314 static gint
315 gtk_menu_bar_expose (GtkWidget      *widget,
316                      GdkEventExpose *event)
317 {
318   GtkMenuShell *menu_shell;
319   GdkEventExpose child_event;
320   GList *children;
321   GtkWidget *child;
322
323   g_return_val_if_fail (widget != NULL, FALSE);
324   g_return_val_if_fail (GTK_IS_MENU_BAR (widget), FALSE);
325   g_return_val_if_fail (event != NULL, FALSE);
326
327   if (GTK_WIDGET_DRAWABLE (widget))
328     {
329       gtk_menu_bar_paint (widget, &event->area);
330
331       menu_shell = GTK_MENU_SHELL (widget);
332       child_event = *event;
333
334       children = menu_shell->children;
335       while (children)
336         {
337           child = children->data;
338           children = children->next;
339
340           if (GTK_WIDGET_NO_WINDOW (child) &&
341               gtk_widget_intersect (child, &event->area, &child_event.area))
342             gtk_widget_event (child, (GdkEvent*) &child_event);
343         }
344     }
345
346   return FALSE;
347 }