Code

fixed typo. removed duplicates of SP_VERB_DIALOG_EXTENSIONEDITOR
[inkscape.git] / src / widgets / toolbox.cpp
1 #define __SP_MAINTOOLBOX_C__
3 /** \file
4  * Controls bars for some of Inkscape's tools 
5  * (for some tools, they are in their own files)
6  */
8 /*
9 *
10 * Authors:
11 *   MenTaLguY <mental@rydia.net>
12 *   Lauris Kaplinski <lauris@kaplinski.com>
13 *   bulia byak <buliabyak@users.sf.net>
14 *   Frank Felfe <innerspace@iname.com>
15 *   John Cliff <simarilius@yahoo.com>
16 *   David Turner <novalis@gnu.org>
17 *   Josh Andler <scislac@scislac.com>
18 *
19 * Copyright (C) 2004 David Turner
20 * Copyright (C) 2003 MenTaLguY
21 * Copyright (C) 1999-2005 authors
22 * Copyright (C) 2001-2002 Ximian, Inc.
23 *
24 * Released under GNU GPL, read the file 'COPYING' for more information
25 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <gtk/gtk.h>
33 #include "widgets/button.h"
34 #include "widgets/widget-sizes.h"
35 #include "widgets/spw-utilities.h"
36 #include "widgets/spinbutton-events.h"
38 #include "prefs-utils.h"
39 #include "verbs.h"
40 #include "sp-namedview.h"
41 #include "desktop.h"
42 #include "desktop-handles.h"
43 #include "nodepath.h"
44 #include "xml/repr.h"
45 #include "xml/node-event-vector.h"
46 #include <glibmm/i18n.h>
47 #include "helper/unit-menu.h"
48 #include "helper/units.h"
50 #include "inkscape.h"
51 #include "conn-avoid-ref.h"
54 #include "select-toolbar.h"
55 #include "gradient-toolbar.h"
57 #include "connector-context.h"
58 #include "sp-rect.h"
59 #include "sp-star.h"
60 #include "sp-spiral.h"
61 #include "sp-ellipse.h"
62 #include "selection.h"
63 #include "document-private.h"
65 #include "mod360.h"
67 #include "toolbox.h"
69 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
70 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
72 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
73 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
74 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
75 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
76 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
77 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
78 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
79 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
80 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
81 static GtkWidget *sp_text_toolbox_new(SPDesktop *desktop);
82 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
85 static struct {
86     gchar const *type_name;
87     gchar const *data_name;
88     sp_verb_t verb;
89     sp_verb_t doubleclick_verb;
90 } const tools[] = {
91     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
92     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
93     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
94     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
95     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
96     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
97     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
98     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
99     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
100     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
101     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
102     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
103     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
104     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
105     { NULL, NULL, 0, 0 }
106 };
108 static struct {
109     gchar const *type_name;
110     gchar const *data_name;
111     GtkWidget *(*create_func)(SPDesktop *desktop);
112 } const aux_toolboxes[] = {
113     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
114     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
115     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
116     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
117     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
118     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
119     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
120     { "SPPencilContext", "pencil_toolbox", NULL },
121     { "SPPenContext", "pen_toolbox", NULL },
122     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
123     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
124     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
125     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
126     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
127     { NULL, NULL, NULL }
128 };
130 static void toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
132 static void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
133 static void update_tool_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
134 static void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
135 static void update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
136 static void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
137 static void update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
139 /* Global text entry widgets necessary for update */
140 /* GtkWidget *dropper_rgb_entry, 
141           *dropper_opacity_entry ; */
142 // should be made a private member once this is converted to class
144 static void delete_connection(GObject *obj, sigc::connection *connection) {
145     connection->disconnect();
146     delete connection;
149 static GtkWidget *
150 sp_toolbox_button_new(GtkWidget *t, GtkIconSize size, gchar const *pxname, GtkSignalFunc handler,
151                       GtkTooltips *tt, gchar const *tip)
153     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
154     gtk_widget_show(b);
155     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
156     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
158     return b;
162 GtkWidget *
163 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, GtkIconSize size, SPButtonType type,
164                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
165                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
167     SPAction *action = verb->get_action(view);
168     if (!action) return NULL;
170     SPAction *doubleclick_action;
171     if (doubleclick_verb)
172         doubleclick_action = doubleclick_verb->get_action(view);
173     else
174         doubleclick_action = NULL;
176     /* fixme: Handle sensitive/unsensitive */
177     /* fixme: Implement sp_button_new_from_action */
178     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
179     gtk_widget_show(b);
180     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
182     return b;
185 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, GtkIconSize size, SPButtonType type, Inkscape::Verb *verb,
186                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
188     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
191 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, GtkIconSize size, Inkscape::Verb *verb,
192                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
194     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
197 GtkWidget *
198 sp_tool_toolbox_new()
200     GtkTooltips *tt = gtk_tooltips_new();
201     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
203     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
204     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
206     gtk_widget_set_sensitive(tb, FALSE);
208     GtkWidget *hb = gtk_handle_box_new();
209     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
210     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
211     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
213     gtk_container_add(GTK_CONTAINER(hb), tb);
214     gtk_widget_show(GTK_WIDGET(tb));
216     sigc::connection* conn = new sigc::connection;
217     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
219     return hb;
222 static void
223 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
225     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
226     gtk_widget_queue_resize(child);
229 static void
230 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
232     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
233     gtk_widget_queue_resize(child);
236 GtkWidget *
237 sp_aux_toolbox_new()
239     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
241     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
242     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
243     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
244     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
245     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
247     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
248     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
250     gtk_widget_set_sensitive(tb, FALSE);
252     GtkWidget *hb = gtk_handle_box_new();
253     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
254     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
255     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
257     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
258     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
260     gtk_container_add(GTK_CONTAINER(hb), tb);
261     gtk_widget_show(GTK_WIDGET(tb));
263     sigc::connection* conn = new sigc::connection;
264     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
266     return hb;
269 //####################################
270 //# Commands Bar
271 //####################################
273 GtkWidget *
274 sp_commands_toolbox_new()
276     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
278     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
279     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
280     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
281     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
282     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
284     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
285     gtk_widget_set_sensitive(tb, FALSE);
287     GtkWidget *hb = gtk_handle_box_new();
288     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
289     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
290     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
292     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
293     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
295     gtk_container_add(GTK_CONTAINER(hb), tb);
296     gtk_widget_show(GTK_WIDGET(tb));
298     sigc::connection* conn = new sigc::connection;
299     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
301     return hb;
305 //####################################
306 //# node editing callbacks
307 //####################################
309 void
310 sp_node_path_edit_add(void)
312     sp_node_selected_add_node();
315 void
316 sp_node_path_edit_delete(void)
318     sp_node_selected_delete();
321 void
322 sp_node_path_edit_delete_segment(void)
324     sp_node_selected_delete_segment();
327 void
328 sp_node_path_edit_break(void)
330     sp_node_selected_break();
333 void
334 sp_node_path_edit_join(void)
336     sp_node_selected_join();
339 void
340 sp_node_path_edit_join_segment(void)
342     sp_node_selected_join_segment();
345 void
346 sp_node_path_edit_toline(void)
348     sp_node_selected_set_line_type(NR_LINETO);
351 void
352 sp_node_path_edit_tocurve(void)
354     sp_node_selected_set_line_type(NR_CURVETO);
357 void
358 sp_node_path_edit_cusp(void)
360     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
363 void
364 sp_node_path_edit_smooth(void)
366     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
369 void
370 sp_node_path_edit_symmetrical(void)
372     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
377 //################################
378 //##    Node Editing Toolbox    ##
379 //################################
381 static GtkWidget *
382 sp_node_toolbox_new(SPDesktop *desktop)
384     Inkscape::UI::View::View *view = desktop;
386     GtkTooltips *tt = gtk_tooltips_new();
387     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
389     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
391     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_insert",
392         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
393     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_delete",
394         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
396     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
398     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_join",
399         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join paths at selected nodes"));
400     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
401         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join paths at selected nodes with new segment"));
403     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
404         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
406     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_break",
407         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
409     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
411     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
412         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
414     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
415         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
417     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
418         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
420     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
422     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_line",
423         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
425     sp_toolbox_button_new(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, "node_curve",
426         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
428     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
430     sp_toolbox_button_normal_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
432     sp_toolbox_button_normal_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
434     gtk_widget_show_all(tb);
436     return tb;
438 } // end of sp_node_toolbox_new()
441 //########################
442 //##    Zoom Toolbox    ##
443 //########################
445 static GtkWidget *
446 sp_zoom_toolbox_new(SPDesktop *desktop)
448     Inkscape::UI::View::View *view=desktop;
450     GtkTooltips *tt = gtk_tooltips_new();
451     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
453     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
454                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
456     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_IN), view, tt);
458     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_OUT), view, tt);
460     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
462     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
464     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
466     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
468     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE_WIDTH), view, tt);
470     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
472     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PREV), view, tt);
474     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_NEXT), view, tt);
476     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
478     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_1), view, tt);
480     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_2), view, tt);
482     sp_toolbox_button_new_from_verb(tb, GTK_ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_2_1), view, tt);
484     gtk_widget_show_all(tb);
486     return tb;
488 } // end of sp_zoom_toolbox_new()
490 void
491 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
493     toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_tool_toolbox, update_tool_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
497 void
498 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
500     toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_aux_toolbox, update_aux_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
503 void
504 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
506     toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_commands_toolbox, update_commands_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
510 static void
511 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
513     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
514     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
516     if (old_desktop) {
517         GList *children, *iter;
519         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
520         for ( iter = children ; iter ; iter = iter->next ) {
521             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
522         }
523         g_list_free(children);
524     }
526     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
528     if (desktop) {
529         gtk_widget_set_sensitive(toolbox, TRUE);
530         setup_func(toolbox, desktop);
531         update_func(desktop, desktop->event_context, toolbox);
532         *conn = desktop->connectEventContextChanged 
533             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
534     } else {
535         gtk_widget_set_sensitive(toolbox, FALSE);
536     }
538 } // end of toolbox_set_desktop()
541 static void
542 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
544     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
545     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
546     GtkIconSize toolboxSize = shrinkLeft ? GTK_ICON_SIZE_SMALL_TOOLBAR : GTK_ICON_SIZE_LARGE_TOOLBAR;
548     for (int i = 0 ; tools[i].type_name ; i++ ) {
549         GtkWidget *button =
550             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
551                                                               SP_BUTTON_TYPE_TOGGLE,
552                                                               Inkscape::Verb::get(tools[i].verb),
553                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
554                                                               desktop,
555                                                               tooltips );
557         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
558                            (gpointer)button );
559     }
563 static void
564 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
566     gchar const *const tname = ( eventcontext
567                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
568                                  : NULL );
569     for (int i = 0 ; tools[i].type_name ; i++ ) {
570         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
571         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
572     }
575 static void
576 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
578     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
580     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
581         GtkWidget *sub_toolbox;
582         if (aux_toolboxes[i].create_func == NULL)
583             sub_toolbox = sp_empty_toolbox_new(desktop);
584         else
585             sub_toolbox = aux_toolboxes[i].create_func(desktop);
587         gtk_size_group_add_widget( grouper, sub_toolbox );
589         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
590         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
591     }
592     g_object_unref( G_OBJECT(grouper) );
595 static void
596 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
598     gchar const *tname = ( eventcontext
599                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
600                            : NULL );
601     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
602         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
603         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
604             gtk_widget_show_all(sub_toolbox);
605             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
606         } else {
607             gtk_widget_hide(sub_toolbox);
608         }
609     }
612 static void
613 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
615     Inkscape::UI::View::View *view = desktop;
617     GtkTooltips *tt = gtk_tooltips_new();
618     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
620     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
621     GtkIconSize toolboxSize = shrinkTop ? GTK_ICON_SIZE_SMALL_TOOLBAR : GTK_ICON_SIZE_LARGE_TOOLBAR;
623     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
624     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
625     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
626     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
628     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
630     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
631     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
633     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
635     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
636     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
638     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
640     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
641     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
642     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
644     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
646     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
647     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
648     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
650     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
652     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
653     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
654     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
656     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
658     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
659     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
661     // disabled until we have icons for them:
663     //find
665     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
666     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
668     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
670     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
671     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
672     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
673     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
675     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
677     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
678     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
680     gtk_widget_show_all(tb);
682     gtk_container_add(GTK_CONTAINER(toolbox), tb);
685 static void
686 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
690 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
692     gtk_widget_show(toolbox_toplevel);
693     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
695     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
696     if (!shown_toolbox) {
697         return;
698     }
699     gtk_widget_show(toolbox);
701     // need to show the spacer, or the padding will be off
702     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
703     gtk_widget_show(spacer);
705     gtk_widget_show_all(shown_toolbox);
708 void
709 aux_toolbox_space(GtkWidget *tb, gint space)
711     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
714 static GtkWidget *
715 sp_empty_toolbox_new(SPDesktop *desktop)
717     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
718     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
719     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
721     gtk_widget_show_all(tbl);
722     sp_set_font_size_smaller (tbl);
724     return tbl;
727 // helper UI functions
729 GtkWidget *
730 sp_tb_spinbutton(
731     gchar *label, gchar const *tooltip,
732     gchar const *path, gchar const *data, gdouble def,
733     GtkWidget *us,
734     GtkWidget *tbl,
735     gboolean altx, gchar const *altx_mark,
736     gdouble lower, gdouble upper, gdouble step, gdouble page,
737     void (*callback)(GtkAdjustment *, GtkWidget *),
738     gdouble climb = 0.1, guint digits = 3)
740     GtkTooltips *tt = gtk_tooltips_new();
742     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
744     GtkWidget *l = gtk_label_new(label);
745     gtk_widget_show(l);
746     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
747     gtk_container_add(GTK_CONTAINER(hb), l);
749     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def),
750                                       lower, upper, step, page, page);
751     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
752     if (us)
753         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
755     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
756     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
757     if (altx)
758         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
759     gtk_widget_set_size_request(sb, AUX_SPINBUTTON_WIDTH_SMALL, AUX_SPINBUTTON_HEIGHT);
760     gtk_widget_show(sb);
761     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
762     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
763     gtk_container_add(GTK_CONTAINER(hb), sb);
764     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
766     return hb;
769 #define MODE_LABEL_WIDTH 70
771 //########################
772 //##       Star         ##
773 //########################
775 static void
776 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
778     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
780     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
781         // do not remember prefs if this call is initiated by an undo change, because undoing object
782         // creation sets bogus values to its attributes before it is deleted
783         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
784     }
786     // quit if run by the attr_changed listener
787     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
788         return;
789     }
791     // in turn, prevent listener from responding
792     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
794     bool modmade = false;
796     Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
797     GSList const *items = selection->itemList();
798     for (; items != NULL; items = items->next) {
799         if (SP_IS_STAR((SPItem *) items->data)) {
800             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
801             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
802             sp_repr_set_svg_double(repr, "sodipodi:arg2",
803                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
804                                     + M_PI / (gint)adj->value));
805             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
806             modmade = true;
807         }
808     }
809     if (modmade)  sp_document_done(SP_DT_DOCUMENT(desktop));
811     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
813     spinbutton_defocus(GTK_OBJECT(tbl));
816 static void
817 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
819     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
821     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
822         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
823     }
825     // quit if run by the attr_changed listener
826     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
827         return;
828     }
830     // in turn, prevent listener from responding
831     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
833     bool modmade = false;
834     Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
835     GSList const *items = selection->itemList();
836     for (; items != NULL; items = items->next) {
837         if (SP_IS_STAR((SPItem *) items->data)) {
838             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
840             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
841             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
842             if (r2 < r1) {
843                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
844             } else {
845                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
846             }
848             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
849             modmade = true;
850         }
851     }
853     if (modmade) sp_document_done(SP_DT_DOCUMENT(desktop));
855     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
857     spinbutton_defocus(GTK_OBJECT(tbl));
860 static void
861 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
863     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
865     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
866         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
867             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
868         } else {
869             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
870         }
871     }
873     // quit if run by the attr_changed listener
874     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
875         return;
876     }
878     // in turn, prevent listener from responding
879     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
881     Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
882     GSList const *items = selection->itemList();
883     GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
884     bool modmade = false;
885     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
886         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
887         for (; items != NULL; items = items->next) {
888             if (SP_IS_STAR((SPItem *) items->data)) {
889                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
890                 repr->setAttribute("inkscape:flatsided", "true");
891                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
892                 modmade = true;
893             }
894         }
895     } else {
896         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
897         for (; items != NULL; items = items->next) {
898             if (SP_IS_STAR((SPItem *) items->data)) {
899                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
900                 repr->setAttribute("inkscape:flatsided", "false");
901                 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
902                 modmade = true;
903             }
904         }
905     }
906     if (modmade) sp_document_done(SP_DT_DOCUMENT(desktop));
908     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
910     spinbutton_defocus(GTK_OBJECT(tbl));
913 static void
914 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
916     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
918     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
919         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
920     }
922     // quit if run by the attr_changed listener
923     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
924         return;
925     }
927     // in turn, prevent listener from responding
928     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
930     bool modmade = false;
932     Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
933     GSList const *items = selection->itemList();
934     for (; items != NULL; items = items->next) {
935         if (SP_IS_STAR((SPItem *) items->data)) {
936             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
937             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
938             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
939             modmade = true;
940         }
941     }
942     if (modmade)  sp_document_done(SP_DT_DOCUMENT(desktop));
944     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
946     spinbutton_defocus(GTK_OBJECT(tbl));
950 static void
951 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
953     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
955     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
956         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
957     }
959     // quit if run by the attr_changed listener
960     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
961         return;
962     }
964     // in turn, prevent listener from responding
965     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
967     bool modmade = false;
969     Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
970     GSList const *items = selection->itemList();
971     for (; items != NULL; items = items->next) {
972         if (SP_IS_STAR((SPItem *) items->data)) {
973             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
974             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
975             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
976             modmade = true;
977         }
978     }
979     if (modmade)  sp_document_done(SP_DT_DOCUMENT(desktop));
981     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
983     spinbutton_defocus(GTK_OBJECT(tbl));
987 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
988                                        gchar const *old_value, gchar const *new_value,
989                                        bool is_interactive, gpointer data)
991     GtkWidget *tbl = GTK_WIDGET(data);
993     // quit if run by the _changed callbacks
994     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
995         return;
996     }
998     // in turn, prevent callbacks from responding
999     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1001     GtkAdjustment *adj;
1003     if (!strcmp(name, "inkscape:randomized")) {
1004         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1005         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1006     } else if (!strcmp(name, "inkscape:rounded")) {
1007         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1008         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1009     } else if (!strcmp(name, "inkscape:flatsided")) {
1010         GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1011         GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1012         char const *flatsides = repr->attribute("inkscape:flatsided");
1013         if (flatsides && !strcmp(flatsides,"false" )) {
1014             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1015             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1016         } else {
1017             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1018             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1019         }
1020     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1021         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1022         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1023         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1024         if (r2 < r1) {
1025             gtk_adjustment_set_value(adj, r2/r1);
1026         } else {
1027             gtk_adjustment_set_value(adj, r1/r2);
1028         }
1029     } else if (!strcmp(name, "sodipodi:sides")) {
1030         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1031         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1032     }
1034     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1038 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1040     NULL, /* child_added */
1041     NULL, /* child_removed */
1042     star_tb_event_attr_changed,
1043     NULL, /* content_changed */
1044     NULL  /* order_changed */
1045 };
1048 /**
1049  *  \param selection Should not be NULL.
1050  */
1051 static void
1052 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1054     int n_selected = 0;
1055     Inkscape::XML::Node *repr = NULL;
1056     Inkscape::XML::Node *oldrepr = NULL;
1058     for (GSList const *items = selection->itemList();
1059          items != NULL;
1060          items = items->next)
1061     {
1062         if (SP_IS_STAR((SPItem *) items->data)) {
1063             n_selected++;
1064             repr = SP_OBJECT_REPR((SPItem *) items->data);
1065         }
1066     }
1068     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1070     if (n_selected == 0) {
1071         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1072     } else if (n_selected == 1) {
1073         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1075         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1076         if (oldrepr) { // remove old listener
1077             sp_repr_remove_listener_by_data(oldrepr, tbl);
1078             Inkscape::GC::release(oldrepr);
1079             oldrepr = 0;
1080             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1081         }
1083         if (repr) {
1084             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1085             Inkscape::GC::anchor(repr);
1086             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1087             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1088         }
1089     } else {
1090         // FIXME: implement averaging of all parameters for multiple selected stars
1091         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1092         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1093     }
1097 static void
1098 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1100     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1101     // callbacks to lump all the changes for all selected objects in one undo step
1103     GtkAdjustment *adj;
1105     // fixme: make settable in prefs!
1106     gint mag = 5;
1107     gdouble prop = 0.5;
1108     gboolean flat = FALSE;
1109     gdouble randomized = 0;
1110     gdouble rounded = 0;
1112     GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1113     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  flat);
1114     GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1115     gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1117     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1118     gtk_adjustment_set_value(adj, mag);
1119     gtk_adjustment_value_changed(adj);
1121     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1122     gtk_adjustment_set_value(adj, prop);
1123     gtk_adjustment_value_changed(adj);
1125     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1126     gtk_adjustment_set_value(adj, rounded);
1127     gtk_adjustment_value_changed(adj);
1129     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1130     gtk_adjustment_set_value(adj, randomized);
1131     gtk_adjustment_value_changed(adj);
1133     spinbutton_defocus(GTK_OBJECT(tbl));
1137 void
1138 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1140     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1141     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1142     GtkWidget *l = gtk_label_new(NULL);
1143     gtk_label_set_markup(GTK_LABEL(l), title);
1144     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1145     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1146     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1150 static GtkWidget *
1151 sp_star_toolbox_new(SPDesktop *desktop)
1153     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1155     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1156     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1158     GtkTooltips *tt = gtk_tooltips_new();
1160     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1162     gchar const *flatsidedstr = NULL;
1164     /* Flatsided checkbox */
1165     {
1166         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1167         GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1168         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1169         flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1170         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1171             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1172         else
1173             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1174         gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1175         gtk_widget_show(fscb);
1176         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1177         gtk_container_add(GTK_CONTAINER(hb), fscb);
1178         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1179         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1180     }
1182     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1184     /* Magnitude */
1185     {
1186         GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1187                                          "tools.shapes.star", "magnitude", 3,
1188                                          NULL, tbl, TRUE, "altx-star",
1189                                          3, 1024, 1, 1,
1190                                          sp_stb_magnitude_value_changed, 1, 0);
1191         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1192     }
1194     /* Spoke ratio */
1195     {
1196         GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1197                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1198                                          // Base radius is the same for the closest handle.
1199                                          _("Base radius to tip radius ratio"),
1200                                          "tools.shapes.star", "proportion", 0.5,
1201                                          NULL, tbl, FALSE, NULL,
1202                                          0.01, 1.0, 0.01, 0.1,
1203                                          sp_stb_proportion_value_changed);
1204         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1205         g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1206         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1207             gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1208         else
1209             gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1210     }
1212     /* Roundedness */
1213     {
1214         GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1215                                          "tools.shapes.star", "rounded", 0.0,
1216                                          NULL, tbl, FALSE, NULL,
1217                                          -100.0, 100.0, 0.01, 0.1,
1218                                          sp_stb_rounded_value_changed);
1219         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1220     }
1222     /* Randomization */
1223     {
1224         GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1225                                          "tools.shapes.star", "randomized", 0.0,
1226                                          NULL, tbl, FALSE, NULL,
1227                                          -10.0, 10.0, 0.001, 0.01,
1228                                          sp_stb_randomized_value_changed, 0.1, 3);
1229         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1230     }
1232     aux_toolbox_space(tbl, AUX_SPACING);
1234     /* Reset */
1235     {
1236         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1237         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1238         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1239         gtk_widget_show(b);
1240         gtk_container_add(GTK_CONTAINER(hb), b);
1241         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1242         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1243     }
1245     gtk_widget_show_all(tbl);
1246     sp_set_font_size_smaller (tbl);
1248     sigc::connection *connection = new sigc::connection(
1249         SP_DT_SELECTION(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1250         );
1251     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1253     return tbl;
1257 //########################
1258 //##       Rect         ##
1259 //########################
1261 static void 
1262 sp_rtb_sensitivize (GtkWidget *tbl)
1264     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1265     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1266     GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1268     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1269         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1270     } else {
1271         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1272     }
1276 static void
1277 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1278                           void (*setter)(SPRect *, gdouble))
1280     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1282     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1283     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1285     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
1286         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1287     }
1289     // quit if run by the attr_changed listener
1290     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1291         return;
1292     }
1294     // in turn, prevent listener from responding
1295     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1297     bool modmade = false;
1298     Inkscape::Selection *selection = SP_DT_SELECTION(desktop);
1299     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1300         if (SP_IS_RECT(items->data)) {
1301             if (adj->value != 0) {
1302                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1303             } else {
1304                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1305             }
1306             modmade = true;
1307         }
1308     }
1310     sp_rtb_sensitivize (tbl);
1312     if (modmade) {
1313         sp_document_done(SP_DT_DOCUMENT(desktop));
1314     }
1316     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1318     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1319     spinbutton_defocus(GTK_OBJECT(tbl));
1322 static void
1323 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1325     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1328 static void
1329 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1331     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1334 static void
1335 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1337     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1340 static void
1341 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1343     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1348 static void
1349 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1351     GtkWidget *tbl = GTK_WIDGET(obj);
1353     GtkAdjustment *adj;
1355     adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1356     gtk_adjustment_set_value(adj, 0.0);
1357     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1358     gtk_adjustment_value_changed(adj);
1360     adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1361     gtk_adjustment_set_value(adj, 0.0);
1362     gtk_adjustment_value_changed(adj);
1364     sp_rtb_sensitivize (tbl);
1366     spinbutton_defocus(GTK_OBJECT(tbl));
1369 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1370                                        gchar const *old_value, gchar const *new_value,
1371                                        bool is_interactive, gpointer data)
1373     GtkWidget *tbl = GTK_WIDGET(data);
1375     // quit if run by the _changed callbacks
1376     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1377         return;
1378     }
1380     // in turn, prevent callbacks from responding
1381     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1383     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1384     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1386     SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1387     if (SP_IS_RECT(item)) {
1388         {
1389             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1390             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1391             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1392         }
1394         {
1395             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1396             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1397             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1398         }
1400         {
1401             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1402             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1403             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1404         }
1406         {
1407             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1408             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1409             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1410         }
1411     }
1413     sp_rtb_sensitivize (tbl);
1415     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1419 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1420     NULL, /* child_added */
1421     NULL, /* child_removed */
1422     rect_tb_event_attr_changed,
1423     NULL, /* content_changed */
1424     NULL  /* order_changed */
1425 };
1427 /**
1428  *  \param selection should not be NULL.
1429  */
1430 static void
1431 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1433     int n_selected = 0;
1434     Inkscape::XML::Node *repr = NULL;
1435     SPItem *item = NULL;
1436     Inkscape::XML::Node *oldrepr = NULL;
1438     for (GSList const *items = selection->itemList();
1439          items != NULL;
1440          items = items->next) {
1441         if (SP_IS_RECT((SPItem *) items->data)) {
1442             n_selected++;
1443             item = (SPItem *) items->data;
1444             repr = SP_OBJECT_REPR(item);
1445         }
1446     }
1448     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1450     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1452     if (n_selected == 0) {
1453         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1455         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1456         gtk_widget_set_sensitive(w, FALSE);
1457         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1458         gtk_widget_set_sensitive(h, FALSE);
1460     } else if (n_selected == 1) {
1461         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1462         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1464         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1465         gtk_widget_set_sensitive(w, TRUE);
1466         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1467         gtk_widget_set_sensitive(h, TRUE);
1469         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1470         if (oldrepr) { // remove old listener
1471             sp_repr_remove_listener_by_data(oldrepr, tbl);
1472             Inkscape::GC::release(oldrepr);
1473             oldrepr = 0;
1474             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1475         }
1476         if (repr) {
1477             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1478             g_object_set_data(G_OBJECT(tbl), "item", item);
1479             Inkscape::GC::anchor(repr);
1480             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1481             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1482         }
1483     } else {
1484         // FIXME: implement averaging of all parameters for multiple selected
1485         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1486         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1487         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1488     }
1492 static GtkWidget *
1493 sp_rect_toolbox_new(SPDesktop *desktop)
1495     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1497     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1498     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1500     GtkTooltips *tt = gtk_tooltips_new();
1502     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1504     // rx/ry units menu: create
1505     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1506     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1507     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1508     // fixme: add % meaning per cent of the width/height
1510     /* W */
1511     {
1512         GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1513                                          "tools.shapes.rect", "width", 0,
1514                                          us, tbl, TRUE, "altx-rect",
1515                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1516                                          sp_rtb_width_value_changed);
1517         gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1518         gtk_widget_set_sensitive(hb, FALSE);
1519         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1520     }
1522     /* H */
1523     {
1524         GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1525                                          "tools.shapes.rect", "height", 0,
1526                                          us, tbl, FALSE, NULL,
1527                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1528                                          sp_rtb_height_value_changed);
1529         gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1530         gtk_widget_set_sensitive(hb, FALSE);
1531         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1532     }
1534     /* rx */
1535     {
1536         GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1537                                          "tools.shapes.rect", "rx", 0,
1538                                          us, tbl, FALSE, NULL,
1539                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1540                                          sp_rtb_rx_value_changed);
1541         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1542     }
1544     /* ry */
1545     {
1546         GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1547                                          "tools.shapes.rect", "ry", 0,
1548                                          us, tbl, FALSE, NULL,
1549                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1550                                          sp_rtb_ry_value_changed);
1551         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1552     }
1554     // add the units menu
1555     gtk_widget_show(us);
1556     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1557     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1559     /* Reset */
1560     {
1561         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1562         GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1563         gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1564         gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1565         gtk_widget_show(b);
1566         gtk_container_add(GTK_CONTAINER(hb), b);
1567         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1568         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1569     }
1571     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1572     sp_rtb_sensitivize (tbl);
1574     gtk_widget_show_all(tbl);
1575     sp_set_font_size_smaller (tbl);
1577     sigc::connection *connection = new sigc::connection(
1578         SP_DT_SELECTION(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1579         );
1580     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1582     return tbl;
1585 //########################
1586 //##       Spiral       ##
1587 //########################
1589 static void
1590 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1592     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1594     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
1595         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1596     }
1598     // quit if run by the attr_changed listener
1599     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1600         return;
1601     }
1603     // in turn, prevent listener from responding
1604     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1606     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1608     bool modmade = false;
1609     for (GSList const *items = SP_DT_SELECTION(desktop)->itemList();
1610          items != NULL;
1611          items = items->next)
1612     {
1613         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1614             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1615             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1616             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1617             modmade = true;
1618         }
1619     }
1621     g_free(namespaced_name);
1623     if (modmade) {
1624         sp_document_done(SP_DT_DOCUMENT(desktop));
1625     }
1627     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1629     spinbutton_defocus(GTK_OBJECT(tbl));
1632 static void
1633 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1635     sp_spl_tb_value_changed(adj, tbl, "revolution");
1638 static void
1639 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1641     sp_spl_tb_value_changed(adj, tbl, "expansion");
1644 static void
1645 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1647     sp_spl_tb_value_changed(adj, tbl, "t0");
1650 static void
1651 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1653     GtkWidget *tbl = GTK_WIDGET(obj);
1655     GtkAdjustment *adj;
1657     // fixme: make settable
1658     gdouble rev = 5;
1659     gdouble exp = 1.0;
1660     gdouble t0 = 0.0;
1662     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1663     gtk_adjustment_set_value(adj, rev);
1664     gtk_adjustment_value_changed(adj);
1666     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1667     gtk_adjustment_set_value(adj, exp);
1668     gtk_adjustment_value_changed(adj);
1670     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1671     gtk_adjustment_set_value(adj, t0);
1672     gtk_adjustment_value_changed(adj);
1674     spinbutton_defocus(GTK_OBJECT(tbl));
1678 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1679                                          gchar const *old_value, gchar const *new_value,
1680                                          bool is_interactive, gpointer data)
1682     GtkWidget *tbl = GTK_WIDGET(data);
1684     // quit if run by the _changed callbacks
1685     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1686         return;
1687     }
1689     // in turn, prevent callbacks from responding
1690     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1692     GtkAdjustment *adj;
1693     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1694     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1696     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1697     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1699     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1700     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1702     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1706 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1707     NULL, /* child_added */
1708     NULL, /* child_removed */
1709     spiral_tb_event_attr_changed,
1710     NULL, /* content_changed */
1711     NULL  /* order_changed */
1712 };
1714 static void
1715 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1717     int n_selected = 0;
1718     Inkscape::XML::Node *repr = NULL;
1719     Inkscape::XML::Node *oldrepr = NULL;
1721     for (GSList const *items = selection->itemList();
1722          items != NULL;
1723          items = items->next)
1724     {
1725         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1726             n_selected++;
1727             repr = SP_OBJECT_REPR((SPItem *) items->data);
1728         }
1729     }
1731     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1733     if (n_selected == 0) {
1734         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1735     } else if (n_selected == 1) {
1736         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1738         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1739         if (oldrepr) { // remove old listener
1740             sp_repr_remove_listener_by_data(oldrepr, tbl);
1741             Inkscape::GC::release(oldrepr);
1742             oldrepr = 0;
1743             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1744         }
1746         if (repr) {
1747             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1748             Inkscape::GC::anchor(repr);
1749             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1750             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1751         }
1752     } else {
1753         // FIXME: implement averaging of all parameters for multiple selected
1754         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1755         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1756     }
1760 static GtkWidget *
1761 sp_spiral_toolbox_new(SPDesktop *desktop)
1763     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1764     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1765     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1767     GtkTooltips *tt = gtk_tooltips_new();
1769     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1771     /* Revolution */
1772     {
1773         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1774                                          "tools.shapes.spiral", "revolution", 3.0,
1775                                          NULL, tbl, TRUE, "altx-spiral",
1776                                          0.01, 1024.0, 0.1, 1.0,
1777                                          sp_spl_tb_revolution_value_changed, 1, 2);
1778         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1779     }
1781     /* Expansion */
1782     {
1783         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1784                                          "tools.shapes.spiral", "expansion", 1.0,
1785                                          NULL, tbl, FALSE, NULL,
1786                                          0.0, 1000.0, 0.01, 1.0,
1787                                          sp_spl_tb_expansion_value_changed);
1788         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1789     }
1791     /* T0 */
1792     {
1793         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1794                                          "tools.shapes.spiral", "t0", 0.0,
1795                                          NULL, tbl, FALSE, NULL,
1796                                          0.0, 0.999, 0.01, 1.0,
1797                                          sp_spl_tb_t0_value_changed);
1798         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1799     }
1801     aux_toolbox_space(tbl, AUX_SPACING);
1803     /* Reset */
1804     {
1805         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1806         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1807         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1808         gtk_widget_show(b);
1809         gtk_container_add(GTK_CONTAINER(hb), b);
1810         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1811         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1812     }
1814     gtk_widget_show_all(tbl);
1815     sp_set_font_size_smaller (tbl);
1817     sigc::connection *connection = new sigc::connection(
1818         SP_DT_SELECTION(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1819         );
1820     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1822     return tbl;
1826 //########################
1827 //##     Calligraphy    ##
1828 //########################
1830 static void
1831 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1833     prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1834     spinbutton_defocus(GTK_OBJECT(tbl));
1837 static void
1838 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1840     prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1841     spinbutton_defocus(GTK_OBJECT(tbl));
1844 static void
1845 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1847     prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1848     spinbutton_defocus(GTK_OBJECT(tbl));
1851 static void
1852 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1854     prefs_set_double_attribute("tools.calligraphic", "width", adj->value);
1855     spinbutton_defocus(GTK_OBJECT(tbl));
1858 static void
1859 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1861     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1862     spinbutton_defocus(GTK_OBJECT(tbl));
1865 static void
1866 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1868     prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1869     spinbutton_defocus(GTK_OBJECT(tbl));
1872 static void
1873 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1875     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1878 static void
1879 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1881     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1883     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1886 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
1888     // FIXME: make defaults settable via Inkscape Options
1889     struct KeyValue {
1890         char const *key;
1891         double value;
1892     } const key_values[] = {
1893         {"mass", 0.02},
1894         {"drag", 1.0},
1895         {"angle", 30.0},
1896         {"width", 0.15},
1897         {"thinning", 0.1},
1898         {"flatness", 0.9}
1899     };
1901     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
1902         KeyValue const &kv = key_values[i];
1903         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
1904         gtk_adjustment_set_value(&adj, kv.value);
1905     }
1907     spinbutton_defocus(GTK_OBJECT(tbl));
1910 static GtkWidget *
1911 sp_calligraphy_toolbox_new(SPDesktop *desktop)
1913     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1914     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1915     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1917     GtkTooltips *tt = gtk_tooltips_new();
1918     GtkWidget *calligraphy_angle;
1920     //  interval
1921     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1923     /* Width */
1924     {
1925         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
1926                                          "tools.calligraphic", "width", 0.15,
1927                                          NULL, tbl, TRUE, "altx-calligraphy",
1928                                          0.01, 1.0, 0.01, 0.1,
1929                                          sp_ddc_width_value_changed,  0.01, 2);
1930         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1931     }
1933     /* Thinning */
1934     {
1935         GtkWidget *hb = sp_tb_spinbutton(_("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
1936                                          "tools.calligraphic", "thinning", 0.1,
1937                                          NULL, tbl, FALSE, NULL,
1938                                          -1.0, 1.0, 0.01, 0.1,
1939                                          sp_ddc_velthin_value_changed, 0.01, 2);
1940         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1941     }
1943     //  interval
1944     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1946     /* Angle */
1947     {
1948         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
1949                                              "tools.calligraphic", "angle", 30,
1950                                              NULL, tbl, TRUE, "calligraphy-angle",
1951                                              -90.0, 90.0, 1.0, 10.0,
1952                                              sp_ddc_angle_value_changed, 1, 0);
1953         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
1954     }
1956     /* Fixation */
1957     {
1958         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
1959                                          "tools.calligraphic", "flatness", 0.9,
1960                                          NULL, tbl, FALSE, NULL,
1961                                          0.0, 1.0, 0.01, 0.1,
1962                                          sp_ddc_flatness_value_changed, 0.01, 2);
1963         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1964     }
1966     //  interval
1967     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1969     /* Mass */
1970     {
1971         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
1972                                          "tools.calligraphic", "mass", 0.02,
1973                                          NULL, tbl, FALSE, NULL,
1974                                          0.0, 1.0, 0.01, 0.1,
1975                                          sp_ddc_mass_value_changed, 0.01, 2);
1976         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1977     }
1979     /* Drag */
1980     {
1981         // TRANSLATORS: "drag" means "resistance" here
1982         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
1983                                          "tools.calligraphic", "drag", 1,
1984                                          NULL, tbl, FALSE, NULL,
1985                                          0.0, 1.0, 0.01, 0.1,
1986                                          sp_ddc_drag_value_changed, 0.01, 2);
1987         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1988     }
1990     //  interval
1991     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1993     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
1994     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
1996     /* Use Pressure button */
1997     {
1998     GtkWidget *button = sp_button_new_from_data( GTK_ICON_SIZE_SMALL_TOOLBAR,
1999                                                  SP_BUTTON_TYPE_TOGGLE,
2000                                                  NULL,
2001                                                  "use_pressure",
2002                                                  _("Use the pressure of the input device to alter the width of the pen"),
2003                                                  tt);
2004     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2005     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2006     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2007     }
2009     /* Use Tilt button */
2010     {
2011     GtkWidget *button = sp_button_new_from_data( GTK_ICON_SIZE_SMALL_TOOLBAR,
2012                                                  SP_BUTTON_TYPE_TOGGLE,
2013                                                  NULL,
2014                                                  "use_tilt",
2015                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2016                                                  tt);
2017     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2018     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2019     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2020     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2021     }
2023     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2024     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2026     /* Reset */
2027     {
2028         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2029         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2030         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2031         gtk_widget_show(b);
2032         gtk_container_add(GTK_CONTAINER(hb), b);
2033         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2034         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2035     }
2037 /*
2038      // Tablet features
2039     {
2040         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2041         GtkWidget *fscb = gtk_check_button_new_with_label(_("Tablet"));
2042         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
2047         gtk_tooltips_set_tip(tt, fscb, _("Enable/Disable drawing tablet features"), NULL);
2048         gtk_widget_show(fscb);
2049         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
2050         gtk_container_add(GTK_CONTAINER(hb), fscb);
2052         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
2053     }
2054 */
2056     gtk_widget_show_all(tbl);
2057     sp_set_font_size_smaller (tbl);
2059     return tbl;
2063 //########################
2064 //##    Circle / Arc    ##
2065 //########################
2067 static void 
2068 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2070     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2071     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2073     if (v1 == 0 && v2 == 0) {
2074         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2075             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2076             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2077         }
2078     } else {
2079         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2080         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2081     }
2084 static void
2085 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2087     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2089     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
2090         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2091     }
2093     // quit if run by the attr_changed listener
2094     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2095         return;
2096     }
2098     // in turn, prevent listener from responding
2099     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2101     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2103     bool modmade = false;
2104     for (GSList const *items = SP_DT_SELECTION(desktop)->itemList();
2105          items != NULL;
2106          items = items->next)
2107     {
2108         SPItem *item = SP_ITEM(items->data);
2110         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2112             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2113             SPArc *arc = SP_ARC(item);
2115             if (!strcmp(value_name, "start"))
2116                 ge->start = (adj->value * M_PI)/ 180;
2117             else
2118                 ge->end = (adj->value * M_PI)/ 180;
2120             sp_genericellipse_normalize(ge);
2121             ((SPObject *)arc)->updateRepr();
2122             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2124             modmade = true;
2125         }
2126     }
2128     g_free(namespaced_name);
2130     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2132     sp_arctb_sensitivize (tbl, adj->value, other->value);
2134     if (modmade) {
2135         sp_document_maybe_done(SP_DT_DOCUMENT(desktop), value_name);
2136     }
2138     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2139     spinbutton_defocus(GTK_OBJECT(tbl));
2141     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2145 static void
2146 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2148     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2151 static void
2152 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2154     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2157 static void
2158 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2160     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2162     if (sp_document_get_undo_sensitive(SP_DT_DOCUMENT(desktop))) {
2163         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2164             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2165         } else {
2166             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2167         }
2168     }
2170     // quit if run by the attr_changed listener
2171     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2172         return;
2173     }
2175     // in turn, prevent listener from responding
2176     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2178     bool modmade = false;
2180     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2181         for (GSList const *items = SP_DT_SELECTION(desktop)->itemList();
2182              items != NULL;
2183              items = items->next)
2184         {
2185             if (SP_IS_ARC((SPItem *) items->data)) {
2186                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2187                 repr->setAttribute("sodipodi:open", "true");
2188                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2189                 modmade = true;
2190             }
2191         }
2192     } else {
2193         for (GSList const *items = SP_DT_SELECTION(desktop)->itemList();
2194              items != NULL;
2195              items = items->next)
2196         {
2197             if (SP_IS_ARC((SPItem *) items->data))    {
2198                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2199                 repr->setAttribute("sodipodi:open", NULL);
2200                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2201                 modmade = true;
2202             }
2203         }
2204     }
2206     if (modmade) {
2207         sp_document_done(SP_DT_DOCUMENT(desktop));
2208     }
2210     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2212     spinbutton_defocus(GTK_OBJECT(tbl));
2215 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2217     GtkWidget *tbl = GTK_WIDGET(obj);
2219     GtkAdjustment *adj;
2220     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2221     gtk_adjustment_set_value(adj, 0.0);
2222     gtk_adjustment_value_changed(adj);
2224     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2225     gtk_adjustment_set_value(adj, 0.0);
2226     gtk_adjustment_value_changed(adj);
2228     spinbutton_defocus(GTK_OBJECT(tbl));
2231 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2232                                       gchar const *old_value, gchar const *new_value,
2233                                       bool is_interactive, gpointer data)
2235     GtkWidget *tbl = GTK_WIDGET(data);
2237     // quit if run by the _changed callbacks
2238     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2239         return;
2240     }
2242     // in turn, prevent callbacks from responding
2243     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2245     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2246     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2248     GtkAdjustment *adj1,*adj2;
2249     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2250     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2251     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2252     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2254     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2256     char const *openstr = NULL;
2257     openstr = repr->attribute("sodipodi:open");
2258     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2260     if (openstr) {
2261         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2262     } else {
2263         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2264     }
2266     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2269 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2270     NULL, /* child_added */
2271     NULL, /* child_removed */
2272     arc_tb_event_attr_changed,
2273     NULL, /* content_changed */
2274     NULL  /* order_changed */
2275 };
2278 static void
2279 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2281     int n_selected = 0;
2282     Inkscape::XML::Node *repr = NULL;
2283     Inkscape::XML::Node *oldrepr = NULL;
2285     for (GSList const *items = selection->itemList();
2286          items != NULL;
2287          items = items->next)
2288     {
2289         if (SP_IS_ARC((SPItem *) items->data)) {
2290             n_selected++;
2291             repr = SP_OBJECT_REPR((SPItem *) items->data);
2292         }
2293     }
2295     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2297     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2298     if (n_selected == 0) {
2299         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2300     } else if (n_selected == 1) {
2301         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2302         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2304         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2306         if (oldrepr) { // remove old listener
2307             sp_repr_remove_listener_by_data(oldrepr, tbl);
2308             Inkscape::GC::release(oldrepr);
2309             oldrepr = 0;
2310             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2311         }
2313         if (repr) {
2314             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2315             Inkscape::GC::anchor(repr);
2316             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2317             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2318         }
2319     } else {
2320         // FIXME: implement averaging of all parameters for multiple selected
2321         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2322         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2323         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2324     }
2328 static GtkWidget *
2329 sp_arc_toolbox_new(SPDesktop *desktop)
2331     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2333     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2334     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2336     GtkTooltips *tt = gtk_tooltips_new();
2338     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2340     /* Start */
2341     {
2342         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2343                                          "tools.shapes.arc", "start", 0.0,
2344                                          NULL, tbl, TRUE, "altx-arc",
2345                                          -360.0, 360.0, 1.0, 10.0,
2346                                          sp_arctb_start_value_changed);
2347         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2348     }
2350     /* End */
2351     {
2352         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2353                                          "tools.shapes.arc", "end", 0.0,
2354                                          NULL, tbl, FALSE, NULL,
2355                                          -360.0, 360.0, 1.0, 10.0,
2356                                          sp_arctb_end_value_changed);
2357         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2358     }
2360     /* Segments / Pie checkbox */
2361     {
2362         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2363         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2364         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2366         gchar const *openstr = NULL;
2367         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2368         if (!openstr || (openstr && !strcmp(openstr, "false")))
2369             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2370         else
2371             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2373         gtk_widget_show(fscb);
2374         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2375         gtk_container_add(GTK_CONTAINER(hb), fscb);
2376         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2377         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2378     }
2380     /* Make Whole */
2381     {
2382         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2383         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2384         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2385         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2386         gtk_widget_show(b);
2387         gtk_container_add(GTK_CONTAINER(hb), b);
2388         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2389         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2390     }
2392     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2393     // sensitivize make whole and open checkbox
2394     {
2395         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2396         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2397         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2398     }
2400     sigc::connection *connection = new sigc::connection(
2401         SP_DT_SELECTION(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2402         );
2403     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2405     gtk_widget_show_all(tbl);
2406     sp_set_font_size_smaller (tbl);
2408     return tbl;
2414 // toggle button callbacks and updaters
2416 //########################
2417 //##      Dropper       ##
2418 //########################
2420 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2421     prefs_set_int_attribute ("tools.dropper", "pick", 
2422         // 0 and 1 are backwards here because of pref
2423         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2427 /**
2428  * Copy the current saved desktop color to the clipboard as full hex + alpha
2429  * color representation. This is useful for passing values between various 
2430  * input boxes, or directly to xml.
2431  */
2432 /* static void
2433 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2435     GtkWidget *tbl = GTK_WIDGET(obj);
2436     
2437     SPDesktop *desktop = 
2438         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2440    
2441     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2442 }*/
2445 /**
2446  * Copies currently saved desktop color to the clipboard as a hex value. This 
2447  * is useful for editing webpages and needing a value quickly for web
2448  * colors.
2449  * 
2450  * TODO: When the toggle of the dropper is set to not mix color against 
2451  *       page background, this still just gets the color of the page and 
2452  *       doesn't get the actual mixed against background which is needed 
2453  *       for the hex value ppl. want for web pages, etc.
2454  */
2456 /* static void
2457 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2459     GtkWidget *tbl = GTK_WIDGET(obj);
2460     
2461     SPDesktop *desktop = 
2462         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2463     
2464     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2465 }*/
2468 /**
2469  * Sets the input boxes with the changed color and opacity. This is used as a 
2470  * callback for style changing.
2471  */
2472 /* static bool
2473 sp_style_changed (const SPCSSAttr *css, gpointer data)
2475     // GrDrag *drag = (GrDrag *) data;
2476     
2477     // set fill of text entry box
2478     if (css->attribute("fill"))
2479         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2480             css->attribute("fill")); 
2482     // set opacity of text entry box
2483     if (css->attribute("fill-opacity"))
2484         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2485             css->attribute("fill-opacity")); 
2486     
2487     // set fill of text entry box
2488     if (css->attribute("stroke"))
2489         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2490             css->attribute("stroke")); 
2492     // set opacity of text entry box
2493     if (css->attribute("stroke-opacity"))
2494         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2495             css->attribute("stroke-opacity"));
2496     return false;
2499 */
2502 /**
2503  * Dropper auxiliary toolbar construction and setup.
2504  *
2505  * TODO: Would like to add swatch of current color.
2506  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2507  *       can drag and drop places. Will provide a nice mixing palette.
2508  */
2509 static GtkWidget *
2510 sp_dropper_toolbox_new(SPDesktop *desktop)
2512     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2514     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2515     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2517     GtkTooltips *tt = gtk_tooltips_new();
2519     
2520     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2521                        AUX_BETWEEN_BUTTON_GROUPS);
2522     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2525     
2526     /* RGB Input Field */
2527  /*   {
2528         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2529         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2530         gtk_widget_show (dropper_rgba_label);
2531         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2532         
2533         dropper_rgb_entry = gtk_entry_new ();
2534         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2535         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2536         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2537         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2538                          _("Hexidecimal representation of last selected "
2539                            "color"), 
2540                          NULL);
2541         gtk_widget_show (dropper_rgb_entry);
2542         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2543         
2544         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2545                            AUX_BETWEEN_BUTTON_GROUPS);
2546     } */
2547     
2548     /* Opacity Input Field */
2549 /*    {
2550         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2551         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2552         gtk_widget_show (dropper_opacity_label);
2553         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2554         
2555         dropper_opacity_entry = gtk_entry_new ();
2556         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2557         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2558         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2559         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2560                          _("Opacity of last selected color"), 
2561                          NULL);
2562         gtk_widget_show (dropper_opacity_entry);
2563         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2564         
2565         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2566                            AUX_BETWEEN_BUTTON_GROUPS);
2567     } */
2568     
2569     
2570     /* Copy to Clipboard */
2571 /*    {
2572         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2573         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2574         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2575                                       "RGB + Alpha (RGBA) to "
2576                                       "clipboard"), 
2577                              NULL);
2578         gtk_widget_show(b);
2579         gtk_container_add(GTK_CONTAINER(hb), b);
2580         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2581             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2582         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2583                            AUX_BETWEEN_BUTTON_GROUPS);
2584     } */
2587     /* Copy to Clipboard as HEX */
2588 /*    {
2589         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2590         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2591         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2592                                       "hexidecimal RGB without alpha " 
2593                                       "to clipboard"), NULL);
2594         gtk_widget_show(b);
2595         gtk_container_add(GTK_CONTAINER(hb), b);
2596         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2597             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2598         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2599                            AUX_BETWEEN_BUTTON_GROUPS);
2600     } */
2601     
2602     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2603     
2604     {
2605         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2606         
2607         GtkWidget *button = 
2608             sp_button_new_from_data( GTK_ICON_SIZE_SMALL_TOOLBAR,
2609                                      SP_BUTTON_TYPE_TOGGLE,
2610                                      NULL,
2611                                      "pick_color",
2612                                      _("When pressed, picks visible color "
2613                                        "without alpha and when not pressed, "
2614                                        "picks color including its "
2615                                        "alpha"),
2616                                      tt);
2618         gtk_widget_show(button);
2619         gtk_container_add (GTK_CONTAINER (hb), button);
2621         g_signal_connect_after (G_OBJECT (button), "clicked", 
2622                                 G_CALLBACK (toggle_dropper_color_pick), NULL);
2623         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2624                                       !prefs_get_int_attribute ("tools.dropper", 
2625                                                                "pick", 0));
2626         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2627                    AUX_BETWEEN_BUTTON_GROUPS);
2628     }
2629    
2630     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2631     
2633     // where new gtkmm stuff should go
2634     
2635     gtk_widget_show_all(tbl);
2636     sp_set_font_size_smaller (tbl);
2638     /*
2639     sigc::connection *connection = new sigc::connection(
2640         desktop->connectSetStyle(
2641             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2642                        desktop)) ); 
2643     
2644     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2645                      connection); */
2646     
2647     return tbl;
2651 //########################
2652 //##    Text Toolbox    ##
2653 //########################
2654 /*
2655 static void
2656 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2658     //Call back for letter sizing spinbutton
2661 static void
2662 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2664     //Call back for line height spinbutton
2667 static void
2668 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2670     //Call back for horizontal kerning spinbutton
2673 static void
2674 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2676     //Call back for vertical kerning spinbutton
2679 static void
2680 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2682     //Call back for letter rotation spinbutton
2683 }*/
2684 static GtkWidget *
2685 sp_text_toolbox_new(SPDesktop *desktop)
2687     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2688 /*    GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
2689     GtkTooltips *tt = gtk_tooltips_new();
2690     GtkWidget *group;
2692         //Font Family
2693         {
2694         GtkWidget *c = gtk_combo_new ();
2695         gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2696         gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2697         gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2698         gtk_widget_set_size_request (c, 144, -1);
2699         aux_toolbox_space(tbl, 1);
2700         gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2701         }
2703         //Font Style
2704         {
2705         GtkWidget *c = gtk_combo_new ();
2706         gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2707         gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2708         gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2709         gtk_widget_set_size_request (c, 88, -1);
2710         aux_toolbox_space(tbl, 1);
2711         gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2712         }
2714         //Font Size
2715         {
2716         GtkWidget *c = gtk_combo_new ();
2717         gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2718         gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2719         gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2720         gtk_widget_set_size_request (c, 64, -1);
2721         aux_toolbox_space(tbl, 1);
2722         gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2723         }
2725         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2726         //Bold
2727         {
2728         GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR);
2729         GtkWidget *button = gtk_toggle_button_new ();
2730         gtk_container_add (GTK_CONTAINER (button), px);
2731         gtk_widget_show(button);
2732         gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
2733         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2734         gtk_widget_set_sensitive(button, TRUE);
2735         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2736         }
2739         //Italic
2740         {
2741         GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR);
2742         GtkWidget *button = gtk_toggle_button_new ();
2743         gtk_container_add (GTK_CONTAINER (button), px);
2744         gtk_widget_show(button);
2745         gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
2746         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2747         gtk_widget_set_sensitive(button, TRUE);
2748         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2749         }
2751         //Underline
2752         {
2753         GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, GTK_ICON_SIZE_SMALL_TOOLBAR);
2754         GtkWidget *button = gtk_toggle_button_new ();
2755         gtk_container_add (GTK_CONTAINER (button), px);
2756         gtk_widget_show(button);
2757         gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
2758         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2759         gtk_widget_set_sensitive(button, FALSE);
2760         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2761         }
2763         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2764         // align left
2765         {
2766         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR);
2767         GtkWidget *b = group = gtk_radio_button_new (NULL);
2768                 gtk_container_add (GTK_CONTAINER (b), px);
2769         gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
2770         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2771         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2772         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2773         }
2775         // align center
2776         {
2777         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR);
2778         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2779                 gtk_container_add (GTK_CONTAINER (b), px);
2780         // TRANSLATORS: `Center' here is a verb.
2781         gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
2782                 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2783         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2784         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2785         }
2787         // align right
2788         {
2789         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR);
2790         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2791                 gtk_container_add (GTK_CONTAINER (b), px);
2792         gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
2793         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2794         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2795         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2796         }
2798         // full justification
2799         {
2800         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR);
2801         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2802                 gtk_container_add (GTK_CONTAINER (b), px);
2803         gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
2804         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2805         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2806         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2807         }
2808         
2809                 
2810         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2811                 
2812         // horizontal
2813         {
2814         GtkWidget *px= sp_icon_new(GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
2815         GtkWidget *b = group = gtk_radio_button_new (NULL);
2816                 gtk_container_add (GTK_CONTAINER (b), px);
2817         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
2818         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2819         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2820         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2821         }
2823         // vertical
2824         {
2825         GtkWidget *px = sp_icon_new (GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
2826         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2827                 gtk_container_add (GTK_CONTAINER (b), px);
2828         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
2829         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2830         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2831         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2832         }
2834         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2836         // letter spacing
2837     {
2838         {
2839         GtkWidget *image = sp_icon_new (GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
2840         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2841         gtk_container_add (GTK_CONTAINER (hb), image);
2842         gtk_widget_show(image);
2843         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2844         }
2845     
2846         {
2847             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
2848                                              "tools.text", "letter_spacing", 0.0,
2849                                              us, tbl, FALSE, NULL,
2850                                              -1000.0, 1000.0, 0.1, 0.1,
2851                                              sp_text_letter_changed, 0.1, 1);
2852             gtk_widget_set_size_request (hb, 45, 6);
2853             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
2854         }
2855     }
2857         // line spacing
2858     {
2859         {
2860         GtkWidget *image = sp_icon_new (GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
2861         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2862         gtk_container_add (GTK_CONTAINER (hb), image);
2863         gtk_widget_show(image);
2864         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2865         }
2866     
2867         {
2868             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
2869                                              "tools.text", "line_spacing", 0,
2870                                              us, tbl, FALSE, NULL,
2871                                              -1000.0, 1000.0, 0.1, 0.1,
2872                                              sp_text_line_changed, 0.1, 1);
2873             gtk_widget_set_size_request (hb, 45, 0);
2874             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
2875         }
2876     }
2879     // horizontal kerning/vertical kerning units menu: create
2880     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
2881     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
2882     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
2884     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2886     // horizontal kerning
2887     {
2888         {
2889         GtkWidget *image = sp_icon_new (GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
2890         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2891         gtk_container_add (GTK_CONTAINER (hb), image);
2892         gtk_widget_show(image);
2893         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2894         }
2896         {
2897             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
2898                                              "tools.text", "horizontal_kerning", 0,
2899                                              us, tbl, FALSE, NULL,
2900                                              -100.00, 100.00, 0.01, 0.1,
2901                                              sp_text_horiz_kern_changed);
2902             gtk_widget_set_size_request (hb, 45, 0);
2903             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
2904         }
2905     }
2907     // vertical kerning
2908     {
2909         {
2910         GtkWidget *image = sp_icon_new (GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
2911         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2912         gtk_container_add (GTK_CONTAINER (hb), image);
2913         gtk_widget_show(image);
2914         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2915         }
2916     
2917         {
2918             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
2919                                              "tools.text", "vertical_kerning", 0,
2920                                              us, tbl, FALSE, NULL,
2921                                              -100.00, 100.00, 0.01, 0.1,
2922                                              sp_text_vert_kern_changed);
2923             gtk_widget_set_size_request (hb, 45, 0);
2924             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
2925         }
2926     }
2928     // add the units menu
2929     gtk_widget_show(us);
2930     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
2931     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
2932     }
2934         // letter rotation
2935     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2936     {
2937         {
2938         GtkWidget *image = sp_icon_new (GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
2939         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2940         gtk_container_add (GTK_CONTAINER (hb), image);
2941         gtk_widget_show(image);
2942         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2943         }
2944         {
2945             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
2946                                              "tools.text", "letter_rotation", 0,
2947                                              us, tbl, FALSE, NULL,
2948                                              -180.0, 180.0, 0.1, 0.1,
2949                                              sp_text_letter_rotation_changed, 0.1, 1);
2950             gtk_widget_set_size_request (hb, 45, 0);
2951             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
2952         }
2953         // rotation degree label
2954         {
2955         GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
2956         gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
2957         }
2958     }
2959         
2960         // Remove Manual Kerns
2961         {
2962         GtkWidget *px = sp_icon_new (GTK_ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
2963         GtkWidget *button = gtk_button_new ();
2964         gtk_container_add (GTK_CONTAINER (button), px);
2965         gtk_widget_show(button);
2966         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
2967         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2968         gtk_widget_set_sensitive(button, TRUE);
2969         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2970         }
2972     gtk_widget_show_all(tbl);
2973     sp_set_font_size_smaller (tbl);
2975 */    return tbl;
2977 } // end of sp_text_toolbox_new()
2980 //#########################
2981 //##  Connector Toolbox  ##
2982 //#########################
2984 static void sp_connector_path_set_avoid(void)
2986     cc_selection_set_avoid(true);
2990 static void sp_connector_path_set_ignore(void)
2992     cc_selection_set_avoid(false);
2996 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
2998     // quit if run by the _changed callbacks
2999     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3000         return;
3001     }
3002         
3003     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3004             "desktop");
3005     SPDocument *doc = SP_DT_DOCUMENT(desktop);
3007     if (!sp_document_get_undo_sensitive(doc))
3008     {
3009         return;
3010     }
3012     // in turn, prevent callbacks from responding
3013     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3014     
3015     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3016     
3017     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3018     SP_OBJECT(desktop->namedview)->updateRepr();
3019     
3020     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3021     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3022         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3023         NR::Matrix m = NR::identity();
3024         avoid_item_move(&m, item);
3025     }
3027     if (items) {
3028         g_slist_free(items);
3029     }
3030     
3031     sp_document_done(doc);
3033     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3034     
3035     spinbutton_defocus(GTK_OBJECT(tbl));
3039 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3040         gchar const *name, gchar const *old_value, gchar const *new_value,
3041         bool is_interactive, gpointer data)
3043     GtkWidget *tbl = GTK_WIDGET(data);
3045     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3046         return;
3047     }
3048     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3049         return;
3050     }
3052     GtkAdjustment *adj = (GtkAdjustment*)
3053             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3054     gdouble spacing = defaultConnSpacing;
3055     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3056     
3057     gtk_adjustment_set_value(adj, spacing);
3061 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3062     NULL, /* child_added */
3063     NULL, /* child_removed */
3064     connector_tb_event_attr_changed,
3065     NULL, /* content_changed */
3066     NULL  /* order_changed */
3067 };
3070 static GtkWidget *
3071 sp_connector_toolbox_new(SPDesktop *desktop)
3073     GtkTooltips *tt = gtk_tooltips_new();
3074     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3075     
3076     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3077     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3079     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3080             AUX_BETWEEN_BUTTON_GROUPS);
3082     sp_toolbox_button_new(tbl, GTK_ICON_SIZE_SMALL_TOOLBAR,
3083             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3084             tt, _("Make connectors avoid selected objects"));
3086     sp_toolbox_button_new(tbl, GTK_ICON_SIZE_SMALL_TOOLBAR,
3087             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3088             tt, _("Make connectors ignore selected objects"));
3090     //  interval
3091     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3092             AUX_BETWEEN_BUTTON_GROUPS);
3094     // Spacing spinbox
3095     {
3096         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3097                 _("The amount of space left around objects by auto-routing connectors"),
3098                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3099                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3100                 connector_spacing_changed, 1, 0);
3102         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3103                 AUX_SPACING);
3104     }
3106     gtk_widget_show_all(tbl);
3107     sp_set_font_size_smaller (tbl);
3108     
3109     // Code to watch for changes to the connector-spacing attribute in
3110     // the XML.
3111     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3112     g_assert(repr != NULL);
3113         
3114     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3115             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3116     
3117     if (oldrepr) { // remove old listener
3118         sp_repr_remove_listener_by_data(oldrepr, tbl);
3119         Inkscape::GC::release(oldrepr);
3120         oldrepr = NULL;
3121         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3122     }
3124     if (repr) {
3125         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3126         Inkscape::GC::anchor(repr);
3127         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3128         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3129     }
3130     
3131     return tbl;
3133 } // end of sp_connector_toolbox_new()
3136 /*
3137   Local Variables:
3138   mode:c++
3139   c-file-style:"stroustrup"
3140   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3141   indent-tabs-mode:nil
3142   fill-column:99
3143   End:
3144 */
3145 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :