Code

Prevented automatic center docking from happening and added the
[inkscape.git] / src / libgdl / gdl-combo-button.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- 
2  * gdl-combo-button.c
3  * 
4  * Copyright (C) 2003 Jeroen Zwartepoorte
5  *
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <gtk/gtk.h>
27 #include "gdl-tools.h"
28 #include "gdl-combo-button.h"
30 struct _GdlComboButtonPrivate {
31         GtkWidget *default_button;
32         GtkWidget *image;
33         GtkWidget *label;
34         GtkWidget *menu_button;
35         GtkWidget *menu;
36         gboolean   menu_popped_up;
37 };
39 GDL_CLASS_BOILERPLATE (GdlComboButton, gdl_combo_button, GtkHBox, GTK_TYPE_HBOX);
41 static void
42 default_button_clicked_cb (GtkButton *button,
43                            gpointer user_data)
44 {
45         GdlComboButton *combo;
46         GdlComboButtonPrivate *priv;
48         combo = GDL_COMBO_BUTTON (user_data);
49         priv = combo->priv;
51         if (!priv->menu_popped_up)
52                 g_signal_emit_by_name (G_OBJECT (combo),
53                                        "activate-default", NULL);
54 }
56 static gboolean
57 default_button_press_event_cb (GtkWidget *widget,
58                                GdkEventButton *event,
59                                gpointer user_data)
60 {
61         GdlComboButton *combo_button;
62         GdlComboButtonPrivate *priv;
64         combo_button = GDL_COMBO_BUTTON (user_data);
65         priv = combo_button->priv;
67         if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
68                 GTK_BUTTON (priv->menu_button)->button_down = TRUE;
69                 gtk_button_pressed (GTK_BUTTON (priv->menu_button));
70         }
72         return FALSE;
73 }
75 static gboolean
76 default_button_release_event_cb (GtkWidget *widget,
77                                  GdkEventButton *event,
78                                  gpointer user_data)
79 {
80         GdlComboButton *combo_button;
81         GdlComboButtonPrivate *priv;
83         combo_button = GDL_COMBO_BUTTON (user_data);
84         priv = combo_button->priv;
86         if (event->button == 1) {
87                 gtk_button_released (GTK_BUTTON (priv->menu_button));
88         }
90         return FALSE;
91 }
93 static gboolean
94 button_enter_notify_cb (GtkWidget *widget,
95                         GdkEventCrossing *event,
96                         gpointer user_data)
97 {
98         GdlComboButton *combo_button;
99         GdlComboButtonPrivate *priv;
101         combo_button = GDL_COMBO_BUTTON (user_data);
102         priv = combo_button->priv;
104         if (event->detail != GDK_NOTIFY_INFERIOR) {
105                 GTK_BUTTON (priv->default_button)->in_button = TRUE;
106                 GTK_BUTTON (priv->menu_button)->in_button = TRUE;
107                 gtk_button_enter (GTK_BUTTON (priv->default_button));
108                 gtk_button_enter (GTK_BUTTON (priv->menu_button));
109         }
111         return TRUE;
114 static gboolean
115 button_leave_notify_cb (GtkWidget *widget,
116                         GdkEventCrossing *event,
117                         gpointer user_data)
119         GdlComboButton *combo_button;
120         GdlComboButtonPrivate *priv;
122         combo_button = GDL_COMBO_BUTTON (user_data);
123         priv = combo_button->priv;
125         if (priv->menu_popped_up)
126                 return TRUE;
128         if (event->detail != GDK_NOTIFY_INFERIOR) {
129                 GTK_BUTTON (priv->default_button)->in_button = FALSE;
130                 GTK_BUTTON (priv->menu_button)->in_button = FALSE;
131                 gtk_button_leave (GTK_BUTTON (priv->default_button));
132                 gtk_button_leave (GTK_BUTTON (priv->menu_button));
133         }
135         return TRUE;
138 static void
139 menu_position_func (GtkMenu *menu,
140                     gint *x_return,
141                     gint *y_return,
142                     gboolean *push_in,
143                     gpointer user_data)
145         GdlComboButton *combo_button;
146         GdlComboButtonPrivate *priv;
147         GtkAllocation *allocation;
149         combo_button = GDL_COMBO_BUTTON (user_data);
150         priv = combo_button->priv;
151         allocation = &(priv->default_button->allocation);
153         gdk_window_get_origin (priv->default_button->window, x_return, y_return);
155         *x_return += allocation->x; 
156         *y_return += allocation->height;
159 static gboolean
160 menu_button_press_event_cb (GtkWidget *widget,
161                             GdkEventButton *event,
162                             gpointer user_data)
164         GdlComboButton *combo_button;
165         GdlComboButtonPrivate *priv;
167         combo_button = GDL_COMBO_BUTTON (user_data);
168         priv = combo_button->priv;
170         if (event->type == GDK_BUTTON_PRESS && 
171             (event->button == 1 || event->button == 3)) {
172                 GTK_BUTTON (priv->menu_button)->button_down = TRUE;
174                 gtk_button_pressed (GTK_BUTTON (priv->menu_button));
176                 priv->menu_popped_up = TRUE;
177                 gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL,
178                                 menu_position_func, combo_button,
179                                 event->button, event->time);
180         }
182         return TRUE;
185 static void
186 menu_deactivate_cb (GtkMenuShell *menu_shell,
187                     gpointer user_data)
189         GdlComboButton *combo_button;
190         GdlComboButtonPrivate *priv;
192         combo_button = GDL_COMBO_BUTTON (user_data);
193         priv = combo_button->priv;
195         priv->menu_popped_up = FALSE;
197         GTK_BUTTON (priv->menu_button)->button_down = FALSE;
198         GTK_BUTTON (priv->menu_button)->in_button = FALSE;
199         GTK_BUTTON (priv->default_button)->in_button = FALSE;
200         gtk_button_leave (GTK_BUTTON (priv->menu_button));
201         gtk_button_leave (GTK_BUTTON (priv->default_button));
202         gtk_button_clicked (GTK_BUTTON (priv->menu_button));
205 static void
206 menu_detacher (GtkWidget *widget,
207                GtkMenu *menu)
209         GdlComboButton *combo_button;
211         combo_button = GDL_COMBO_BUTTON (widget);
213         g_signal_handlers_disconnect_by_func (G_OBJECT (menu),
214                                               menu_deactivate_cb,
215                                               combo_button);
216         combo_button->priv->menu = NULL;
219 static void
220 gdl_combo_button_destroy (GtkObject *object)
222         GdlComboButton *combo_button;
223         GdlComboButtonPrivate *priv;
225         combo_button = GDL_COMBO_BUTTON (object);
226         priv = combo_button->priv;
228         if (priv) {
229                 g_free (priv);
230                 combo_button->priv = NULL;
231         }
232         
233         (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
236 static void
237 gdl_combo_button_class_init (GdlComboButtonClass *klass)
239         GtkObjectClass *object_class;
240         GtkWidgetClass *widget_class;
242         parent_class = g_type_class_peek_parent (klass);
243         object_class = GTK_OBJECT_CLASS (klass);
244         widget_class = GTK_WIDGET_CLASS (klass);
246         object_class->destroy = gdl_combo_button_destroy;
248         g_signal_new ("activate-default",
249                       G_TYPE_FROM_CLASS (klass),
250                       G_SIGNAL_RUN_FIRST,
251                       G_STRUCT_OFFSET (GdlComboButtonClass, activate_default),
252                       NULL, NULL,
253                       g_cclosure_marshal_VOID__VOID,
254                       G_TYPE_NONE, 0);
257 static void
258 gdl_combo_button_instance_init (GdlComboButton *combo_button)
260         GdlComboButtonPrivate *priv;
261         GtkWidget *hbox, *align, *arrow;
263         priv = g_new (GdlComboButtonPrivate, 1);
264         combo_button->priv = priv;
266         priv->menu = NULL;
267         priv->menu_popped_up = FALSE;
269         priv->default_button = gtk_button_new ();
270         gtk_button_set_relief (GTK_BUTTON (priv->default_button), GTK_RELIEF_NONE);
272         /* Following code copied from gtk_button_construct_child. */
273         priv->label = gtk_label_new ("");
274         gtk_label_set_use_underline (GTK_LABEL (priv->label), TRUE);
275         gtk_label_set_mnemonic_widget (GTK_LABEL (priv->label),
276                                        priv->default_button);
277       
278         priv->image = gtk_image_new ();
279         hbox = gtk_hbox_new (FALSE, 2);
281         align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
282       
283         gtk_box_pack_start (GTK_BOX (hbox), priv->image, FALSE, FALSE, 0);
284         gtk_box_pack_end (GTK_BOX (hbox), priv->label, FALSE, FALSE, 0);
285       
286         gtk_container_add (GTK_CONTAINER (priv->default_button), align);
287         gtk_container_add (GTK_CONTAINER (align), hbox);
288         /* End copied block. */
290         gtk_box_pack_start (GTK_BOX (combo_button), priv->default_button,
291                             FALSE, FALSE, 0);
292         gtk_widget_show_all (priv->default_button);
294         priv->menu_button = gtk_button_new ();
295         gtk_button_set_relief (GTK_BUTTON (priv->menu_button), GTK_RELIEF_NONE);
296         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
297         gtk_container_add (GTK_CONTAINER (priv->menu_button), arrow);
298         gtk_box_pack_start (GTK_BOX (combo_button), priv->menu_button, FALSE,
299                             FALSE, 0);
300         gtk_widget_show_all (priv->menu_button);
302         /* Default button. */
303         g_signal_connect (G_OBJECT (priv->default_button), "clicked",
304                           G_CALLBACK (default_button_clicked_cb), combo_button);
305         g_signal_connect (G_OBJECT (priv->default_button), "button_press_event",
306                           G_CALLBACK (default_button_press_event_cb), combo_button);
307         g_signal_connect (G_OBJECT (priv->default_button), "button_release_event",
308                           G_CALLBACK (default_button_release_event_cb), combo_button);
309         g_signal_connect (G_OBJECT (priv->default_button), "enter_notify_event",
310                           G_CALLBACK (button_enter_notify_cb), combo_button);
311         g_signal_connect (G_OBJECT (priv->default_button), "leave_notify_event",
312                           G_CALLBACK (button_leave_notify_cb), combo_button);
314         /* Menu button. */
315         g_signal_connect (G_OBJECT (priv->menu_button), "button_press_event",
316                           G_CALLBACK (menu_button_press_event_cb), combo_button);
317         g_signal_connect (G_OBJECT (priv->menu_button), "enter_notify_event",
318                           G_CALLBACK (button_enter_notify_cb), combo_button);
319         g_signal_connect (G_OBJECT (priv->menu_button), "leave_notify_event",
320                           G_CALLBACK (button_leave_notify_cb), combo_button);
323 GtkWidget *
324 gdl_combo_button_new (void)
326         GtkWidget *combo_button;
327         
328         combo_button = GTK_WIDGET (g_object_new (GDL_TYPE_COMBO_BUTTON, NULL));
330         return combo_button;
333 void
334 gdl_combo_button_set_icon (GdlComboButton *combo_button,
335                            GdkPixbuf *pixbuf)
337         GdlComboButtonPrivate *priv;
339         g_return_if_fail (GDL_IS_COMBO_BUTTON (combo_button));
340         g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
342         priv = combo_button->priv;
344         gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), pixbuf);
347 void
348 gdl_combo_button_set_label (GdlComboButton *combo_button,
349                             const gchar *label)
351         GdlComboButtonPrivate *priv;
353         g_return_if_fail (GDL_IS_COMBO_BUTTON (combo_button));
354         g_return_if_fail (label != NULL);
356         priv = combo_button->priv;
358         gtk_label_set_text (GTK_LABEL (priv->label), label);
361 void
362 gdl_combo_button_set_menu (GdlComboButton *combo_button,
363                            GtkMenu *menu)
365         GdlComboButtonPrivate *priv;
367         g_return_if_fail (GDL_IS_COMBO_BUTTON (combo_button));
368         g_return_if_fail (GTK_IS_MENU (menu));
370         priv = combo_button->priv;
372         if (priv->menu != NULL)
373                 gtk_menu_detach (GTK_MENU (priv->menu));
375         priv->menu = GTK_WIDGET (menu);
376         if (menu == NULL)
377                 return;
379         gtk_menu_attach_to_widget (menu, GTK_WIDGET (combo_button), menu_detacher);
381         g_signal_connect (G_OBJECT (menu), "deactivate",
382                           G_CALLBACK (menu_deactivate_cb), combo_button);