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);
108 }
110 static void
111 sp_button_destroy (GtkObject *object)
112 {
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);
131 }
133 static void
134 sp_button_size_request (GtkWidget *widget, GtkRequisition *requisition)
135 {
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);
148 }
150 static void
151 sp_button_clicked (GtkButton *button)
152 {
153 SPButton *sp_button=SP_BUTTON (button);
155 if (sp_button->type == SP_BUTTON_TYPE_TOGGLE) {
156 ((GtkButtonClass *) (parent_class))->clicked (button);
157 }
158 }
160 static gint
161 sp_button_process_event (SPButton *button, GdkEvent *event)
162 {
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;
175 }
177 static void
178 sp_button_perform_action (SPButton *button, gpointer /*data*/)
179 {
180 if (button->action) {
181 sp_action_perform (button->action, NULL);
182 }
183 }
186 GtkWidget *
187 sp_button_new( Inkscape::IconSize size, SPButtonType type, SPAction *action, SPAction *doubleclick_action, GtkTooltips *tooltips )
188 {
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;
207 }
209 void
210 sp_button_toggle_set_down (SPButton *button, gboolean down)
211 {
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);
216 }
218 static void
219 sp_button_set_doubleclick_action (SPButton *button, SPAction *action)
220 {
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 }
228 }
230 static void
231 sp_button_set_action (SPButton *button, SPAction *action)
232 {
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 }
257 }
259 static void
260 sp_button_action_set_active (SPAction */*action*/, unsigned int active, void *data)
261 {
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 }
272 }
274 static void
275 sp_button_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
276 {
277 gtk_widget_set_sensitive (GTK_WIDGET (data), sensitive);
278 }
280 static void
281 sp_button_action_set_shortcut (SPAction *action, unsigned int /*shortcut*/, void *data)
282 {
283 SPButton *button=SP_BUTTON (data);
284 if (button->tooltips) {
285 sp_button_set_composed_tooltip (button->tooltips, GTK_WIDGET (button), action);
286 }
287 }
289 static void
290 sp_button_set_composed_tooltip (GtkTooltips *tooltips, GtkWidget *widget, SPAction *action)
291 {
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 }
312 }
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 )
321 {
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;
327 }