Code

6769fa389d9f1889e29f24e925053f0adb3d8f0f
[inkscape.git] / src / widgets / button.cpp
1 #define __SP_BUTTON_C__
3 /*
4  * Generic button widget
5  *
6  * Authors:
7  *   MenTaLguY <mental@rydia.net>
8  *   Lauris Kaplinski <lauris@kaplinski.com>
9  *   bulia byak <buliabyak@users.sf.net>
10  *
11  * Copyright (C) 2002 Lauris Kaplinski
12  *
13  * This code is in public domain
14  */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
21 #if HAVE_STRING_H
22 #endif
27 #include "shortcuts.h"
28 #include "interface.h"
30 #include "icon.h"
31 #include "button.h"
33 static void sp_button_class_init (SPButtonClass *klass);
34 static void sp_button_init (SPButton *button);
35 static void sp_button_destroy (GtkObject *object);
37 static void sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition);
38 static void sp_button_clicked (GtkButton *button);
39 static void sp_button_perform_action (SPButton *button, gpointer data);
40 static gint sp_button_process_event (SPButton *button, GdkEvent *event);
42 static void sp_button_set_action (SPButton *button, SPAction *action);
43 static void sp_button_set_doubleclick_action (SPButton *button, SPAction *action);
44 static void sp_button_action_set_active (SPAction *action, unsigned int active, void *data);
45 static void sp_button_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data);
46 static void sp_button_action_set_shortcut (SPAction *action, unsigned int shortcut, void *data);
47 static void sp_button_set_composed_tooltip (GtkTooltips *tooltips, GtkWidget *widget, SPAction *action);
49 static GtkToggleButtonClass *parent_class;
50 SPActionEventVector button_event_vector = {
51         {NULL},
52          NULL,
53          sp_button_action_set_active,
54          sp_button_action_set_sensitive,
55          sp_button_action_set_shortcut,
56          NULL
57 };
59 GType sp_button_get_type(void)
60 {
61     static GType type = 0;
62     if (!type) {
63         GTypeInfo info = {
64             sizeof(SPButtonClass),
65             0, // base_init
66             0, // base_finalize
67             (GClassInitFunc)sp_button_class_init,
68             0, // class_finalize
69             0, // class_data
70             sizeof(SPButton),
71             0, // n_preallocs
72             (GInstanceInitFunc)sp_button_init,
73             0 // value_table
74         };
75         type = g_type_register_static(GTK_TYPE_TOGGLE_BUTTON, "SPButton", &info, static_cast<GTypeFlags>(0));
76     }
77     return type;
78 }
80 static void
81 sp_button_class_init (SPButtonClass *klass)
82 {
83         GtkObjectClass *object_class=(GtkObjectClass *)klass;
84         GtkWidgetClass *widget_class=(GtkWidgetClass *)klass;
85         GtkButtonClass *button_class=(GtkButtonClass *)klass;
87         parent_class = (GtkToggleButtonClass *)g_type_class_peek_parent (klass);
89         object_class->destroy = sp_button_destroy;
90         widget_class->size_request = sp_button_size_request;
91         button_class->clicked = sp_button_clicked;
92 }
94 static void
95 sp_button_init (SPButton *button)
96 {
97         button->action = NULL;
98         button->doubleclick_action = NULL;
99         button->tooltips = NULL;
101         gtk_container_set_border_width (GTK_CONTAINER (button), 0);
103         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (button), GTK_CAN_FOCUS);
104         GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
106         g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_button_perform_action), NULL);
107         g_signal_connect_after (G_OBJECT (button), "event", G_CALLBACK (sp_button_process_event), NULL);
110 static void
111 sp_button_destroy (GtkObject *object)
113         SPButton *button;
115         button = SP_BUTTON (object);
117         if (button->tooltips) {
118                 g_object_unref (G_OBJECT (button->tooltips));
119                 button->tooltips = NULL;
120         }
122         if (button->action) {
123                 sp_button_set_action (button, NULL);
124         }
126         if (button->doubleclick_action) {
127                 sp_button_set_doubleclick_action (button, NULL);
128         }
130         ((GtkObjectClass *) (parent_class))->destroy (object);
133 static void
134 sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition)
136         GtkWidget *child;
138         child = gtk_bin_get_child (GTK_BIN (widget));
139         if (child) {
140                 gtk_widget_size_request (GTK_WIDGET (child), requisition);
141         } else {
142                 requisition->width = 0;
143                 requisition->height = 0;
144         }
146         requisition->width += 2 + 2 * MAX (2, widget->style->xthickness);
147         requisition->height += 2 + 2 * MAX (2, widget->style->ythickness);
150 static void
151 sp_button_clicked (GtkButton *button)
153         SPButton *sp_button=SP_BUTTON (button);
155         if (sp_button->type == SP_BUTTON_TYPE_TOGGLE) {
156                 ((GtkButtonClass *) (parent_class))->clicked (button);
157         }
160 static gint 
161 sp_button_process_event (SPButton *button, GdkEvent *event)
163         switch (event->type) {
164         case GDK_2BUTTON_PRESS:
165                 if (button->doubleclick_action) {
166                         sp_action_perform (button->doubleclick_action, NULL);
167                 }
168                 return TRUE;
169                 break;
170         default:
171                 break;
172         }
174         return FALSE;
177 static void
178 sp_button_perform_action (SPButton *button, gpointer /*data*/)
180         if (button->action) {
181                 sp_action_perform (button->action, NULL);
182         }
186 GtkWidget *
187 sp_button_new( Inkscape::IconSize size, SPButtonType type, SPAction *action, SPAction *doubleclick_action, GtkTooltips *tooltips )
189         SPButton *button;
191         button = (SPButton *)g_object_new (SP_TYPE_BUTTON, NULL);
193         button->type = type;
194         button->lsize = CLAMP( size, Inkscape::ICON_SIZE_MENU, Inkscape::ICON_SIZE_DECORATION );
195         button->tooltips = tooltips;
197         if (tooltips) g_object_ref ((GObject *) tooltips);
199         sp_button_set_action (button, action);
200         if (doubleclick_action)
201                 sp_button_set_doubleclick_action (button, doubleclick_action);
203         // The Inkscape style is no-relief buttons
204         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
206         return (GtkWidget *) button;
209 void
210 sp_button_toggle_set_down (SPButton *button, gboolean down)
212         g_return_if_fail (button->type == SP_BUTTON_TYPE_TOGGLE);
213         g_signal_handlers_block_by_func (G_OBJECT (button), (gpointer)G_CALLBACK (sp_button_perform_action), NULL);
214         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), (unsigned int)down);
215         g_signal_handlers_unblock_by_func (G_OBJECT (button), (gpointer)G_CALLBACK (sp_button_perform_action), NULL);
218 static void
219 sp_button_set_doubleclick_action (SPButton *button, SPAction *action)
221         if (button->doubleclick_action) {
222                 nr_object_unref ((NRObject *) button->doubleclick_action);
223         }
224         button->doubleclick_action = action;
225         if (action) {
226                 button->doubleclick_action = (SPAction *) nr_object_ref ((NRObject *) action);
227         }
230 static void
231 sp_button_set_action (SPButton *button, SPAction *action)
233         GtkWidget *child;
235         if (button->action) {
236                 nr_active_object_remove_listener_by_data ((NRActiveObject *) button->action, button);
237                 nr_object_unref ((NRObject *) button->action);
238                 child = gtk_bin_get_child (GTK_BIN (button));
239                 if (child) {
240                         gtk_container_remove (GTK_CONTAINER (button), child);
241                 }
242         }
243         button->action = action;
244         if (action) {
245                 button->action = (SPAction *) nr_object_ref ((NRObject *) action);
246                 nr_active_object_add_listener ((NRActiveObject *) action, (NRObjectEventVector *) &button_event_vector, sizeof (SPActionEventVector), button);
247                 if (action->image) {
248                         child = sp_icon_new (button->lsize, action->image);
249                         gtk_widget_show (child);
250                         gtk_container_add (GTK_CONTAINER (button), child);
251                 }
252         }
254         if (button->tooltips) {
255                 sp_button_set_composed_tooltip (button->tooltips, (GtkWidget *) button, action);
256         }
259 static void
260 sp_button_action_set_active (SPAction */*action*/, unsigned int active, void *data)
262         SPButton *button;
263         button = (SPButton *) data;
264         if (button->type != SP_BUTTON_TYPE_TOGGLE) {
265                 return;
266         }
268         /* temporarily lobotomized until SPActions are per-view */
269         if (0 && !active != !SP_BUTTON_IS_DOWN (button)) {
270                 sp_button_toggle_set_down (button, active);
271         }
274 static void
275 sp_button_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
277         gtk_widget_set_sensitive (GTK_WIDGET (data), sensitive);
280 static void
281 sp_button_action_set_shortcut (SPAction *action, unsigned int /*shortcut*/, void *data)
283         SPButton *button=SP_BUTTON (data);
284         if (button->tooltips) {
285                 sp_button_set_composed_tooltip (button->tooltips, GTK_WIDGET (button), action);
286         }
289 static void
290 sp_button_set_composed_tooltip (GtkTooltips *tooltips, GtkWidget *widget, SPAction *action)
292         if (action) {
293                 unsigned int shortcut = sp_shortcut_get_primary (action->verb);
294                 if (shortcut) {
295                         // there's both action and shortcut
297                         gchar        key[256];
298                         sp_ui_shortcut_string (shortcut, key);
300                         gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
301                         gtk_tooltips_set_tip (tooltips, widget, tip, NULL);
302                         g_free (tip);
304                 } else {
305                         // action has no shortcut
306                         gtk_tooltips_set_tip (tooltips, widget, action->tip, NULL);
307                 }
308         } else {
309                 // no action
310                 gtk_tooltips_set_tip (tooltips, widget, NULL, NULL);
311         }
314 GtkWidget *
315 sp_button_new_from_data( Inkscape::IconSize size,
316                          SPButtonType type,
317                          Inkscape::UI::View::View *view,
318                          const gchar *name,
319                          const gchar *tip,
320                          GtkTooltips *tooltips )
322         GtkWidget *button;
323         SPAction *action=sp_action_new(view, name, name, tip, name, 0);
324         button = sp_button_new (size, type, action, NULL, tooltips);
325         nr_object_unref ((NRObject *) action);
326         return button;