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 <gdk/gdkkeysyms.h>
32 #include "icon.h"
33 #include "button.h"
35 static void sp_button_class_init (SPButtonClass *klass);
36 static void sp_button_init (SPButton *button);
37 static void sp_button_destroy (GtkObject *object);
39 static void sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition);
40 static void sp_button_clicked (GtkButton *button);
41 static void sp_button_perform_action (SPButton *button, gpointer data);
42 static gint sp_button_process_event (SPButton *button, GdkEvent *event);
44 static void sp_button_set_action (SPButton *button, SPAction *action);
45 static void sp_button_set_doubleclick_action (SPButton *button, SPAction *action);
46 static void sp_button_action_set_active (SPAction *action, unsigned int active, void *data);
47 static void sp_button_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data);
48 static void sp_button_action_set_shortcut (SPAction *action, unsigned int shortcut, void *data);
49 static void sp_button_set_composed_tooltip (GtkTooltips *tooltips, GtkWidget *widget, SPAction *action);
51 static GtkToggleButtonClass *parent_class;
52 SPActionEventVector button_event_vector = {
53 {NULL},
54 NULL,
55 sp_button_action_set_active,
56 sp_button_action_set_sensitive,
57 sp_button_action_set_shortcut,
58 NULL
59 };
61 GType sp_button_get_type(void)
62 {
63 static GType type = 0;
64 if (!type) {
65 GTypeInfo info = {
66 sizeof(SPButtonClass),
67 0, // base_init
68 0, // base_finalize
69 (GClassInitFunc)sp_button_class_init,
70 0, // class_finalize
71 0, // class_data
72 sizeof(SPButton),
73 0, // n_preallocs
74 (GInstanceInitFunc)sp_button_init,
75 0 // value_table
76 };
77 type = g_type_register_static(GTK_TYPE_TOGGLE_BUTTON, "SPButton", &info, static_cast<GTypeFlags>(0));
78 }
79 return type;
80 }
82 static void
83 sp_button_class_init (SPButtonClass *klass)
84 {
85 GtkObjectClass *object_class=(GtkObjectClass *)klass;
86 GtkWidgetClass *widget_class=(GtkWidgetClass *)klass;
87 GtkButtonClass *button_class=(GtkButtonClass *)klass;
89 parent_class = (GtkToggleButtonClass *)g_type_class_peek_parent (klass);
91 object_class->destroy = sp_button_destroy;
92 widget_class->size_request = sp_button_size_request;
93 button_class->clicked = sp_button_clicked;
94 }
96 static void
97 sp_button_init (SPButton *button)
98 {
99 button->action = NULL;
100 button->doubleclick_action = NULL;
101 button->tooltips = NULL;
103 gtk_container_set_border_width (GTK_CONTAINER (button), 0);
105 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (button), GTK_CAN_FOCUS);
106 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
108 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_button_perform_action), NULL);
109 g_signal_connect_after (G_OBJECT (button), "event", G_CALLBACK (sp_button_process_event), NULL);
110 }
112 static void
113 sp_button_destroy (GtkObject *object)
114 {
115 SPButton *button;
117 button = SP_BUTTON (object);
119 if (button->tooltips) {
120 g_object_unref (G_OBJECT (button->tooltips));
121 button->tooltips = NULL;
122 }
124 if (button->action) {
125 sp_button_set_action (button, NULL);
126 }
128 if (button->doubleclick_action) {
129 sp_button_set_doubleclick_action (button, NULL);
130 }
132 ((GtkObjectClass *) (parent_class))->destroy (object);
133 }
135 static void
136 sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition)
137 {
138 GtkWidget *child;
140 child = gtk_bin_get_child (GTK_BIN (widget));
141 if (child) {
142 gtk_widget_size_request (GTK_WIDGET (child), requisition);
143 } else {
144 requisition->width = 0;
145 requisition->height = 0;
146 }
148 requisition->width += 2 + 2 * MAX (2, widget->style->xthickness);
149 requisition->height += 2 + 2 * MAX (2, widget->style->ythickness);
150 }
152 static void
153 sp_button_clicked (GtkButton *button)
154 {
155 SPButton *sp_button=SP_BUTTON (button);
157 if (sp_button->type == SP_BUTTON_TYPE_TOGGLE) {
158 ((GtkButtonClass *) (parent_class))->clicked (button);
159 }
160 }
162 static gint
163 sp_button_process_event (SPButton *button, GdkEvent *event)
164 {
165 switch (event->type) {
166 case GDK_2BUTTON_PRESS:
167 if (button->doubleclick_action) {
168 sp_action_perform (button->doubleclick_action, NULL);
169 }
170 return TRUE;
171 break;
172 default:
173 break;
174 }
176 return FALSE;
177 }
179 static void
180 sp_button_perform_action (SPButton *button, gpointer /*data*/)
181 {
182 if (button->action) {
183 sp_action_perform (button->action, NULL);
184 }
185 }
188 GtkWidget *
189 sp_button_new( Inkscape::IconSize size, SPButtonType type, SPAction *action, SPAction *doubleclick_action, GtkTooltips *tooltips )
190 {
191 SPButton *button;
193 button = (SPButton *)g_object_new (SP_TYPE_BUTTON, NULL);
195 button->type = type;
196 button->lsize = CLAMP( size, Inkscape::ICON_SIZE_MENU, Inkscape::ICON_SIZE_DECORATION );
197 button->tooltips = tooltips;
199 if (tooltips) g_object_ref ((GObject *) tooltips);
201 sp_button_set_action (button, action);
202 if (doubleclick_action)
203 sp_button_set_doubleclick_action (button, doubleclick_action);
205 // The Inkscape style is no-relief buttons
206 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
208 return (GtkWidget *) button;
209 }
211 void
212 sp_button_toggle_set_down (SPButton *button, gboolean down)
213 {
214 g_return_if_fail (button->type == SP_BUTTON_TYPE_TOGGLE);
215 g_signal_handlers_block_by_func (G_OBJECT (button), (gpointer)G_CALLBACK (sp_button_perform_action), NULL);
216 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), (unsigned int)down);
217 g_signal_handlers_unblock_by_func (G_OBJECT (button), (gpointer)G_CALLBACK (sp_button_perform_action), NULL);
218 }
220 static void
221 sp_button_set_doubleclick_action (SPButton *button, SPAction *action)
222 {
223 if (button->doubleclick_action) {
224 nr_object_unref ((NRObject *) button->doubleclick_action);
225 }
226 button->doubleclick_action = action;
227 if (action) {
228 button->doubleclick_action = (SPAction *) nr_object_ref ((NRObject *) action);
229 }
230 }
232 static void
233 sp_button_set_action (SPButton *button, SPAction *action)
234 {
235 GtkWidget *child;
237 if (button->action) {
238 nr_active_object_remove_listener_by_data ((NRActiveObject *) button->action, button);
239 nr_object_unref ((NRObject *) button->action);
240 child = gtk_bin_get_child (GTK_BIN (button));
241 if (child) {
242 gtk_container_remove (GTK_CONTAINER (button), child);
243 }
244 }
245 button->action = action;
246 if (action) {
247 button->action = (SPAction *) nr_object_ref ((NRObject *) action);
248 nr_active_object_add_listener ((NRActiveObject *) action, (NRObjectEventVector *) &button_event_vector, sizeof (SPActionEventVector), button);
249 if (action->image) {
250 child = sp_icon_new (button->lsize, action->image);
251 gtk_widget_show (child);
252 gtk_container_add (GTK_CONTAINER (button), child);
253 }
254 }
256 if (button->tooltips) {
257 sp_button_set_composed_tooltip (button->tooltips, (GtkWidget *) button, action);
258 }
259 }
261 static void
262 sp_button_action_set_active (SPAction */*action*/, unsigned int active, void *data)
263 {
264 SPButton *button;
265 button = (SPButton *) data;
266 if (button->type != SP_BUTTON_TYPE_TOGGLE) {
267 return;
268 }
270 /* temporarily lobotomized until SPActions are per-view */
271 if (0 && !active != !SP_BUTTON_IS_DOWN (button)) {
272 sp_button_toggle_set_down (button, active);
273 }
274 }
276 static void
277 sp_button_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
278 {
279 gtk_widget_set_sensitive (GTK_WIDGET (data), sensitive);
280 }
282 static void
283 sp_button_action_set_shortcut (SPAction *action, unsigned int /*shortcut*/, void *data)
284 {
285 SPButton *button=SP_BUTTON (data);
286 if (button->tooltips) {
287 sp_button_set_composed_tooltip (button->tooltips, GTK_WIDGET (button), action);
288 }
289 }
291 static void
292 sp_button_set_composed_tooltip (GtkTooltips *tooltips, GtkWidget *widget, SPAction *action)
293 {
294 if (action) {
295 unsigned int shortcut = sp_shortcut_get_primary (action->verb);
296 if (shortcut!=GDK_VoidSymbol) {
297 // there's both action and shortcut
299 gchar* key = sp_shortcut_get_label(shortcut);
301 gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
302 gtk_tooltips_set_tip (tooltips, widget, tip, NULL);
303 g_free (tip);
304 g_free (key);
306 } else {
307 // action has no shortcut
308 gtk_tooltips_set_tip (tooltips, widget, action->tip, NULL);
309 }
310 } else {
311 // no action
312 gtk_tooltips_set_tip (tooltips, widget, NULL, NULL);
313 }
314 }
316 GtkWidget *
317 sp_button_new_from_data( Inkscape::IconSize size,
318 SPButtonType type,
319 Inkscape::UI::View::View *view,
320 const gchar *name,
321 const gchar *tip,
322 GtkTooltips *tooltips )
323 {
324 GtkWidget *button;
325 SPAction *action=sp_action_new(view, name, name, tip, name, 0);
326 button = sp_button_new (size, type, action, NULL, tooltips);
327 nr_object_unref ((NRObject *) action);
328 return button;
329 }