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 };
58 GtkType
59 sp_button_get_type (void)
60 {
61 static GtkType type = 0;
62 if (!type) {
63 GtkTypeInfo info = {
64 "SPButton",
65 sizeof (SPButton),
66 sizeof (SPButtonClass),
67 (GtkClassInitFunc) sp_button_class_init,
68 (GtkObjectInitFunc) sp_button_init,
69 NULL, NULL, NULL
70 };
71 type = gtk_type_unique (GTK_TYPE_TOGGLE_BUTTON, &info);
72 }
73 return type;
74 }
76 static void
77 sp_button_class_init (SPButtonClass *klass)
78 {
79 GtkObjectClass *object_class=(GtkObjectClass *)klass;
80 GtkWidgetClass *widget_class=(GtkWidgetClass *)klass;
81 GtkButtonClass *button_class=(GtkButtonClass *)klass;
83 parent_class = (GtkToggleButtonClass *)g_type_class_peek_parent (klass);
85 object_class->destroy = sp_button_destroy;
86 widget_class->size_request = sp_button_size_request;
87 button_class->clicked = sp_button_clicked;
88 }
90 static void
91 sp_button_init (SPButton *button)
92 {
93 button->action = NULL;
94 button->doubleclick_action = NULL;
95 button->tooltips = NULL;
97 gtk_container_set_border_width (GTK_CONTAINER (button), 0);
99 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (button), GTK_CAN_FOCUS);
100 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
102 g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_button_perform_action), NULL);
103 g_signal_connect_after (G_OBJECT (button), "event", G_CALLBACK (sp_button_process_event), NULL);
104 }
106 static void
107 sp_button_destroy (GtkObject *object)
108 {
109 SPButton *button;
111 button = SP_BUTTON (object);
113 if (button->tooltips) {
114 g_object_unref (G_OBJECT (button->tooltips));
115 button->tooltips = NULL;
116 }
118 if (button->action) {
119 sp_button_set_action (button, NULL);
120 }
122 if (button->doubleclick_action) {
123 sp_button_set_doubleclick_action (button, NULL);
124 }
126 ((GtkObjectClass *) (parent_class))->destroy (object);
127 }
129 static void
130 sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition)
131 {
132 GtkWidget *child;
134 child = gtk_bin_get_child (GTK_BIN (widget));
135 if (child) {
136 gtk_widget_size_request (GTK_WIDGET (child), requisition);
137 } else {
138 requisition->width = 0;
139 requisition->height = 0;
140 }
142 requisition->width += 2 + 2 * MAX (2, widget->style->xthickness);
143 requisition->height += 2 + 2 * MAX (2, widget->style->ythickness);
144 }
146 static void
147 sp_button_clicked (GtkButton *button)
148 {
149 SPButton *sp_button=SP_BUTTON (button);
151 if (sp_button->type == SP_BUTTON_TYPE_TOGGLE) {
152 ((GtkButtonClass *) (parent_class))->clicked (button);
153 }
154 }
156 static gint
157 sp_button_process_event (SPButton *button, GdkEvent *event)
158 {
159 switch (event->type) {
160 case GDK_2BUTTON_PRESS:
161 if (button->doubleclick_action) {
162 sp_action_perform (button->doubleclick_action, NULL);
163 }
164 return TRUE;
165 break;
166 default:
167 break;
168 }
170 return FALSE;
171 }
173 static void
174 sp_button_perform_action (SPButton *button, gpointer data)
175 {
176 if (button->action) {
177 sp_action_perform (button->action, NULL);
178 }
179 }
182 GtkWidget *
183 sp_button_new( Inkscape::IconSize size, SPButtonType type, SPAction *action, SPAction *doubleclick_action, GtkTooltips *tooltips )
184 {
185 SPButton *button;
187 button = (SPButton *)g_object_new (SP_TYPE_BUTTON, NULL);
189 button->type = type;
190 button->lsize = CLAMP( size, Inkscape::ICON_SIZE_MENU, Inkscape::ICON_SIZE_DECORATION );
191 button->tooltips = tooltips;
193 if (tooltips) g_object_ref ((GObject *) tooltips);
195 sp_button_set_action (button, action);
196 if (doubleclick_action)
197 sp_button_set_doubleclick_action (button, doubleclick_action);
199 // The Inkscape style is no-relief buttons
200 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
202 return (GtkWidget *) button;
203 }
205 void
206 sp_button_toggle_set_down (SPButton *button, gboolean down)
207 {
208 g_return_if_fail (button->type == SP_BUTTON_TYPE_TOGGLE);
209 g_signal_handlers_block_by_func (G_OBJECT (button), (gpointer)G_CALLBACK (sp_button_perform_action), NULL);
210 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), (unsigned int)down);
211 g_signal_handlers_unblock_by_func (G_OBJECT (button), (gpointer)G_CALLBACK (sp_button_perform_action), NULL);
212 }
214 static void
215 sp_button_set_doubleclick_action (SPButton *button, SPAction *action)
216 {
217 if (button->doubleclick_action) {
218 nr_object_unref ((NRObject *) button->doubleclick_action);
219 }
220 button->doubleclick_action = action;
221 if (action) {
222 button->doubleclick_action = (SPAction *) nr_object_ref ((NRObject *) action);
223 }
224 }
226 static void
227 sp_button_set_action (SPButton *button, SPAction *action)
228 {
229 GtkWidget *child;
231 if (button->action) {
232 nr_active_object_remove_listener_by_data ((NRActiveObject *) button->action, button);
233 nr_object_unref ((NRObject *) button->action);
234 child = gtk_bin_get_child (GTK_BIN (button));
235 if (child) {
236 gtk_container_remove (GTK_CONTAINER (button), child);
237 }
238 }
239 button->action = action;
240 if (action) {
241 button->action = (SPAction *) nr_object_ref ((NRObject *) action);
242 nr_active_object_add_listener ((NRActiveObject *) action, (NRObjectEventVector *) &button_event_vector, sizeof (SPActionEventVector), button);
243 if (action->image) {
244 child = sp_icon_new (button->lsize, action->image);
245 gtk_widget_show (child);
246 gtk_container_add (GTK_CONTAINER (button), child);
247 }
248 }
250 if (button->tooltips) {
251 sp_button_set_composed_tooltip (button->tooltips, (GtkWidget *) button, action);
252 }
253 }
255 static void
256 sp_button_action_set_active (SPAction *action, unsigned int active, void *data)
257 {
258 SPButton *button;
259 button = (SPButton *) data;
260 if (button->type != SP_BUTTON_TYPE_TOGGLE) {
261 return;
262 }
264 /* temporarily lobotomized until SPActions are per-view */
265 if (0 && !active != !SP_BUTTON_IS_DOWN (button)) {
266 sp_button_toggle_set_down (button, active);
267 }
268 }
270 static void
271 sp_button_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data)
272 {
273 gtk_widget_set_sensitive (GTK_WIDGET (data), sensitive);
274 }
276 static void
277 sp_button_action_set_shortcut (SPAction *action, unsigned int shortcut, void *data)
278 {
279 SPButton *button=SP_BUTTON (data);
280 if (button->tooltips) {
281 sp_button_set_composed_tooltip (button->tooltips, GTK_WIDGET (button), action);
282 }
283 }
285 static void
286 sp_button_set_composed_tooltip (GtkTooltips *tooltips, GtkWidget *widget, SPAction *action)
287 {
288 if (action) {
289 unsigned int shortcut = sp_shortcut_get_primary (action->verb);
290 if (shortcut) {
291 // there's both action and shortcut
293 gchar key[256];
294 sp_ui_shortcut_string (shortcut, key);
296 gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
297 gtk_tooltips_set_tip (tooltips, widget, tip, NULL);
298 g_free (tip);
300 } else {
301 // action has no shortcut
302 gtk_tooltips_set_tip (tooltips, widget, action->tip, NULL);
303 }
304 } else {
305 // no action
306 gtk_tooltips_set_tip (tooltips, widget, NULL, NULL);
307 }
308 }
310 GtkWidget *
311 sp_button_new_from_data( Inkscape::IconSize size,
312 SPButtonType type,
313 Inkscape::UI::View::View *view,
314 const gchar *name,
315 const gchar *tip,
316 GtkTooltips *tooltips )
317 {
318 GtkWidget *button;
319 SPAction *action=sp_action_new(view, name, name, tip, name, 0);
320 button = sp_button_new (size, type, action, NULL, tooltips);
321 nr_object_unref ((NRObject *) action);
322 return button;
323 }