1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 #include "gtkmenuitem.h"
20 #include "gtkoptionmenu.h"
21 #include "gtksignal.h"
24 #define CHILD_LEFT_SPACING 5
25 #define CHILD_RIGHT_SPACING 1
26 #define CHILD_TOP_SPACING 1
27 #define CHILD_BOTTOM_SPACING 1
28 #define OPTION_INDICATOR_WIDTH 12
29 #define OPTION_INDICATOR_HEIGHT 8
30 #define OPTION_INDICATOR_SPACING 2
33 static void gtk_option_menu_class_init (GtkOptionMenuClass *klass);
34 static void gtk_option_menu_init (GtkOptionMenu *option_menu);
35 static void gtk_option_menu_destroy (GtkObject *object);
36 static void gtk_option_menu_size_request (GtkWidget *widget,
37 GtkRequisition *requisition);
38 static void gtk_option_menu_size_allocate (GtkWidget *widget,
39 GtkAllocation *allocation);
40 static void gtk_option_menu_paint (GtkWidget *widget,
42 static void gtk_option_menu_draw (GtkWidget *widget,
44 static gint gtk_option_menu_expose (GtkWidget *widget,
45 GdkEventExpose *event);
46 static gint gtk_option_menu_button_press (GtkWidget *widget,
47 GdkEventButton *event);
48 static void gtk_option_menu_deactivate (GtkMenuShell *menu_shell,
49 GtkOptionMenu *option_menu);
50 static void gtk_option_menu_update_contents (GtkOptionMenu *option_menu);
51 static void gtk_option_menu_remove_contents (GtkOptionMenu *option_menu);
52 static void gtk_option_menu_calc_size (GtkOptionMenu *option_menu);
53 static void gtk_option_menu_position (GtkMenu *menu,
57 static void gtk_option_menu_show_all (GtkWidget *widget);
58 static void gtk_option_menu_hide_all (GtkWidget *widget);
61 static GtkButtonClass *parent_class = NULL;
65 gtk_option_menu_get_type ()
67 static guint option_menu_type = 0;
69 if (!option_menu_type)
71 GtkTypeInfo option_menu_info =
74 sizeof (GtkOptionMenu),
75 sizeof (GtkOptionMenuClass),
76 (GtkClassInitFunc) gtk_option_menu_class_init,
77 (GtkObjectInitFunc) gtk_option_menu_init,
81 option_menu_type = gtk_type_unique (gtk_button_get_type (), &option_menu_info);
84 return option_menu_type;
88 gtk_option_menu_class_init (GtkOptionMenuClass *class)
90 GtkObjectClass *object_class;
91 GtkWidgetClass *widget_class;
92 GtkButtonClass *button_class;
94 object_class = (GtkObjectClass*) class;
95 widget_class = (GtkWidgetClass*) class;
96 button_class = (GtkButtonClass*) class;
98 parent_class = gtk_type_class (gtk_button_get_type ());
100 object_class->destroy = gtk_option_menu_destroy;
102 widget_class->draw = gtk_option_menu_draw;
103 widget_class->draw_focus = NULL;
104 widget_class->size_request = gtk_option_menu_size_request;
105 widget_class->size_allocate = gtk_option_menu_size_allocate;
106 widget_class->expose_event = gtk_option_menu_expose;
107 widget_class->button_press_event = gtk_option_menu_button_press;
108 widget_class->show_all = gtk_option_menu_show_all;
109 widget_class->hide_all = gtk_option_menu_hide_all;
113 gtk_option_menu_init (GtkOptionMenu *option_menu)
115 GTK_WIDGET_UNSET_FLAGS (option_menu, GTK_CAN_FOCUS);
117 option_menu->menu = NULL;
118 option_menu->menu_item = NULL;
119 option_menu->width = 0;
120 option_menu->height = 0;
124 gtk_option_menu_new ()
126 return GTK_WIDGET (gtk_type_new (gtk_option_menu_get_type ()));
130 gtk_option_menu_get_menu (GtkOptionMenu *option_menu)
132 g_return_val_if_fail (option_menu != NULL, NULL);
133 g_return_val_if_fail (GTK_IS_OPTION_MENU (option_menu), NULL);
135 return option_menu->menu;
139 gtk_option_menu_set_menu (GtkOptionMenu *option_menu,
142 g_return_if_fail (option_menu != NULL);
143 g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
144 g_return_if_fail (menu != NULL);
145 g_return_if_fail (GTK_IS_MENU (menu));
147 gtk_option_menu_remove_menu (option_menu);
149 option_menu->menu = menu;
150 gtk_object_ref (GTK_OBJECT (option_menu->menu));
152 gtk_option_menu_calc_size (option_menu);
154 gtk_signal_connect (GTK_OBJECT (option_menu->menu), "deactivate",
155 (GtkSignalFunc) gtk_option_menu_deactivate,
158 if (GTK_WIDGET (option_menu)->parent)
159 gtk_widget_queue_resize (GTK_WIDGET (option_menu));
161 gtk_option_menu_update_contents (option_menu);
165 gtk_option_menu_remove_menu (GtkOptionMenu *option_menu)
167 g_return_if_fail (option_menu != NULL);
168 g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
170 if (option_menu->menu)
172 gtk_option_menu_remove_contents (option_menu);
173 gtk_signal_disconnect_by_data (GTK_OBJECT (option_menu->menu),
176 gtk_object_unref (GTK_OBJECT (option_menu->menu));
177 option_menu->menu = NULL;
182 gtk_option_menu_set_history (GtkOptionMenu *option_menu,
185 GtkWidget *menu_item;
187 g_return_if_fail (option_menu != NULL);
188 g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
190 if (option_menu->menu)
192 gtk_menu_set_active (GTK_MENU (option_menu->menu), index);
193 menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu));
195 if (menu_item != option_menu->menu_item)
197 gtk_option_menu_remove_contents (option_menu);
198 gtk_option_menu_update_contents (option_menu);
205 gtk_option_menu_destroy (GtkObject *object)
207 GtkOptionMenu *option_menu;
209 g_return_if_fail (object != NULL);
210 g_return_if_fail (GTK_IS_OPTION_MENU (object));
212 option_menu = GTK_OPTION_MENU (object);
214 gtk_option_menu_remove_contents (option_menu);
215 if (option_menu->menu)
217 gtk_object_unref (GTK_OBJECT (option_menu->menu));
218 gtk_widget_destroy (option_menu->menu);
221 if (GTK_OBJECT_CLASS (parent_class)->destroy)
222 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
226 gtk_option_menu_size_request (GtkWidget *widget,
227 GtkRequisition *requisition)
229 GtkOptionMenu *option_menu;
232 g_return_if_fail (widget != NULL);
233 g_return_if_fail (GTK_IS_OPTION_MENU (widget));
234 g_return_if_fail (requisition != NULL);
236 option_menu = GTK_OPTION_MENU (widget);
238 requisition->width = ((GTK_CONTAINER (widget)->border_width +
239 GTK_WIDGET (widget)->style->klass->xthickness) * 2 +
241 OPTION_INDICATOR_WIDTH +
242 OPTION_INDICATOR_SPACING * 5 +
243 CHILD_LEFT_SPACING + CHILD_RIGHT_SPACING);
244 requisition->height = ((GTK_CONTAINER (widget)->border_width +
245 GTK_WIDGET (widget)->style->klass->ythickness) * 2 +
246 option_menu->height +
247 CHILD_TOP_SPACING + CHILD_BOTTOM_SPACING);
249 tmp = (requisition->height - option_menu->height +
250 OPTION_INDICATOR_HEIGHT + OPTION_INDICATOR_SPACING * 2);
251 requisition->height = MAX (requisition->height, tmp);
255 gtk_option_menu_size_allocate (GtkWidget *widget,
256 GtkAllocation *allocation)
259 GtkAllocation child_allocation;
261 g_return_if_fail (widget != NULL);
262 g_return_if_fail (GTK_IS_OPTION_MENU (widget));
263 g_return_if_fail (allocation != NULL);
265 widget->allocation = *allocation;
266 if (GTK_WIDGET_REALIZED (widget))
267 gdk_window_move_resize (widget->window,
268 allocation->x, allocation->y,
269 allocation->width, allocation->height);
271 child = GTK_BUTTON (widget)->child;
272 if (child && GTK_WIDGET_VISIBLE (child))
274 child_allocation.x = (GTK_CONTAINER (widget)->border_width +
275 GTK_WIDGET (widget)->style->klass->xthickness);
276 child_allocation.y = (GTK_CONTAINER (widget)->border_width +
277 GTK_WIDGET (widget)->style->klass->ythickness);
278 child_allocation.width = (allocation->width - child_allocation.x * 2 -
279 OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 5 -
280 CHILD_LEFT_SPACING - CHILD_RIGHT_SPACING);
281 child_allocation.height = (allocation->height - child_allocation.y * 2 -
282 CHILD_TOP_SPACING - CHILD_BOTTOM_SPACING);
283 child_allocation.x += CHILD_LEFT_SPACING;
284 child_allocation.y += CHILD_RIGHT_SPACING;
286 gtk_widget_size_allocate (child, &child_allocation);
291 gtk_option_menu_paint (GtkWidget *widget,
294 GdkRectangle restrict_area;
295 GdkRectangle new_area;
297 g_return_if_fail (widget != NULL);
298 g_return_if_fail (GTK_IS_OPTION_MENU (widget));
299 g_return_if_fail (area != NULL);
301 if (GTK_WIDGET_DRAWABLE (widget))
303 restrict_area.x = GTK_CONTAINER (widget)->border_width;
304 restrict_area.y = GTK_CONTAINER (widget)->border_width;
305 restrict_area.width = widget->allocation.width - restrict_area.x * 2;
306 restrict_area.height = widget->allocation.height - restrict_area.y * 2;
308 if (gdk_rectangle_intersect (area, &restrict_area, &new_area))
310 gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (widget));
311 gdk_window_clear_area (widget->window,
312 new_area.x, new_area.y,
313 new_area.width, new_area.height);
315 gtk_draw_shadow (widget->style, widget->window,
316 GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
317 restrict_area.x, restrict_area.y,
318 restrict_area.width, restrict_area.height);
320 gtk_draw_shadow (widget->style, widget->window,
321 GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
322 restrict_area.x + restrict_area.width - restrict_area.x -
323 OPTION_INDICATOR_WIDTH - OPTION_INDICATOR_SPACING * 4,
324 restrict_area.y + (restrict_area.height - OPTION_INDICATOR_HEIGHT) / 2,
325 OPTION_INDICATOR_WIDTH, OPTION_INDICATOR_HEIGHT);
331 gtk_option_menu_draw (GtkWidget *widget,
335 GdkRectangle child_area;
337 g_return_if_fail (widget != NULL);
338 g_return_if_fail (GTK_IS_OPTION_MENU (widget));
339 g_return_if_fail (area != NULL);
341 if (GTK_WIDGET_DRAWABLE (widget))
343 gtk_option_menu_paint (widget, area);
345 child = GTK_BUTTON (widget)->child;
346 if (child && gtk_widget_intersect (child, area, &child_area))
347 gtk_widget_draw (child, &child_area);
352 gtk_option_menu_expose (GtkWidget *widget,
353 GdkEventExpose *event)
356 GdkEventExpose child_event;
359 g_return_val_if_fail (widget != NULL, FALSE);
360 g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE);
361 g_return_val_if_fail (event != NULL, FALSE);
363 if (GTK_WIDGET_DRAWABLE (widget))
365 gtk_option_menu_paint (widget, &event->area);
367 remove_child = FALSE;
368 child = GTK_BUTTON (widget)->child;
372 if (!GTK_OPTION_MENU (widget)->menu)
374 gtk_option_menu_update_contents (GTK_OPTION_MENU (widget));
375 child = GTK_BUTTON (widget)->child;
381 child_event = *event;
383 if (GTK_WIDGET_NO_WINDOW (child) &&
384 gtk_widget_intersect (child, &event->area, &child_event.area))
385 gtk_widget_event (child, (GdkEvent*) &child_event);
388 gtk_option_menu_remove_contents (GTK_OPTION_MENU (widget));
395 gtk_option_menu_button_press (GtkWidget *widget,
396 GdkEventButton *event)
398 GtkOptionMenu *option_menu;
400 g_return_val_if_fail (widget != NULL, FALSE);
401 g_return_val_if_fail (GTK_IS_OPTION_MENU (widget), FALSE);
402 g_return_val_if_fail (event != NULL, FALSE);
404 if ((event->type == GDK_BUTTON_PRESS) &&
405 (event->button == 1))
407 option_menu = GTK_OPTION_MENU (widget);
408 gtk_option_menu_remove_contents (option_menu);
409 gtk_menu_popup (GTK_MENU (option_menu->menu), NULL, NULL,
410 gtk_option_menu_position, option_menu,
411 event->button, event->time);
418 gtk_option_menu_deactivate (GtkMenuShell *menu_shell,
419 GtkOptionMenu *option_menu)
421 g_return_if_fail (menu_shell != NULL);
422 g_return_if_fail (option_menu != NULL);
423 g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
425 gtk_option_menu_update_contents (option_menu);
429 gtk_option_menu_update_contents (GtkOptionMenu *option_menu)
433 g_return_if_fail (option_menu != NULL);
434 g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
436 if (option_menu->menu)
438 gtk_option_menu_remove_contents (option_menu);
440 option_menu->menu_item = gtk_menu_get_active (GTK_MENU (option_menu->menu));
441 if (option_menu->menu_item)
443 child = GTK_BIN (option_menu->menu_item)->child;
446 gtk_container_block_resize (GTK_CONTAINER (option_menu));
447 if (GTK_WIDGET (option_menu)->state != child->state)
448 gtk_widget_set_state (child, GTK_WIDGET (option_menu)->state);
449 gtk_widget_reparent (child, GTK_WIDGET (option_menu));
450 gtk_container_unblock_resize (GTK_CONTAINER (option_menu));
453 gtk_widget_size_request (child, &child->requisition);
454 gtk_widget_size_allocate (GTK_WIDGET (option_menu),
455 &(GTK_WIDGET (option_menu)->allocation));
457 if (GTK_WIDGET_DRAWABLE (option_menu))
458 gtk_widget_queue_draw (GTK_WIDGET (option_menu));
464 gtk_option_menu_remove_contents (GtkOptionMenu *option_menu)
466 g_return_if_fail (option_menu != NULL);
467 g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
469 if (GTK_BUTTON (option_menu)->child)
471 gtk_container_block_resize (GTK_CONTAINER (option_menu));
472 if (GTK_WIDGET (option_menu->menu_item)->state != GTK_BUTTON (option_menu)->child->state)
473 gtk_widget_set_state (GTK_BUTTON (option_menu)->child,
474 GTK_WIDGET (option_menu->menu_item)->state);
475 GTK_WIDGET_UNSET_FLAGS (GTK_BUTTON (option_menu)->child, GTK_MAPPED | GTK_REALIZED);
476 gtk_widget_reparent (GTK_BUTTON (option_menu)->child, option_menu->menu_item);
477 gtk_container_unblock_resize (GTK_CONTAINER (option_menu));
478 option_menu->menu_item = NULL;
483 gtk_option_menu_calc_size (GtkOptionMenu *option_menu)
488 g_return_if_fail (option_menu != NULL);
489 g_return_if_fail (GTK_IS_OPTION_MENU (option_menu));
491 option_menu->width = 0;
492 option_menu->height = 0;
494 if (option_menu->menu)
496 children = GTK_MENU_SHELL (option_menu->menu)->children;
499 child = children->data;
500 children = children->next;
502 if (GTK_WIDGET_VISIBLE (child))
504 gtk_widget_size_request (child, &child->requisition);
506 option_menu->width = MAX (option_menu->width, child->requisition.width);
507 option_menu->height = MAX (option_menu->height, child->requisition.height);
514 gtk_option_menu_position (GtkMenu *menu,
519 GtkOptionMenu *option_menu;
531 g_return_if_fail (user_data != NULL);
532 g_return_if_fail (GTK_IS_OPTION_MENU (user_data));
534 option_menu = GTK_OPTION_MENU (user_data);
536 width = GTK_WIDGET (menu)->allocation.width;
537 height = GTK_WIDGET (menu)->allocation.height;
539 active = gtk_menu_get_active (GTK_MENU (option_menu->menu));
540 children = GTK_MENU_SHELL (option_menu->menu)->children;
541 gdk_window_get_origin (GTK_WIDGET (option_menu)->window, &menu_xpos, &menu_ypos);
543 menu_ypos += GTK_WIDGET (option_menu)->allocation.height / 2 - 2;
546 menu_ypos -= active->requisition.height / 2;
550 child = children->data;
555 menu_ypos -= child->allocation.height;
556 children = children->next;
559 screen_width = gdk_screen_width ();
560 screen_height = gdk_screen_height ();
568 else if ((menu_ypos + height) > screen_height)
570 menu_ypos -= ((menu_ypos + height) - screen_height);
576 if ((menu_xpos + GTK_WIDGET (option_menu)->allocation.width + width) <= screen_width)
577 menu_xpos += GTK_WIDGET (option_menu)->allocation.width;
584 else if ((menu_xpos + width) > screen_width)
585 menu_xpos -= ((menu_xpos + width) - screen_width);
593 gtk_option_menu_show_all (GtkWidget *widget)
595 GtkContainer *container;
596 GtkOptionMenu *option_menu;
598 g_return_if_fail (widget != NULL);
599 g_return_if_fail (GTK_IS_OPTION_MENU (widget));
600 container = GTK_CONTAINER (widget);
601 option_menu = GTK_OPTION_MENU (widget);
603 gtk_widget_show (widget);
604 gtk_container_foreach (container, (GtkCallback) gtk_widget_show_all, NULL);
605 if (option_menu->menu)
606 gtk_widget_show_all (option_menu->menu);
607 if (option_menu->menu_item)
608 gtk_widget_show_all (option_menu->menu_item);
613 gtk_option_menu_hide_all (GtkWidget *widget)
615 GtkContainer *container;
617 g_return_if_fail (widget != NULL);
618 g_return_if_fail (GTK_IS_OPTION_MENU (widget));
619 container = GTK_CONTAINER (widget);
621 gtk_widget_hide (widget);
622 gtk_container_foreach (container, (GtkCallback) gtk_widget_hide_all, NULL);