Code

15dd7f9aeb0daf2c5e2c859ffb0c8ab8522d6e97
[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 <gtkmm.h>
32 #include <gtk/gtk.h>
34 #include "widgets/button.h"
35 #include "widgets/widget-sizes.h"
36 #include "widgets/spw-utilities.h"
37 #include "widgets/spinbutton-events.h"
39 #include "ui/widget/style-swatch.h"
41 #include "prefs-utils.h"
42 #include "verbs.h"
43 #include "sp-namedview.h"
44 #include "desktop.h"
45 #include "desktop-handles.h"
46 #include "nodepath.h"
47 #include "xml/repr.h"
48 #include "xml/node-event-vector.h"
49 #include <glibmm/i18n.h>
50 #include "helper/unit-menu.h"
51 #include "helper/units.h"
53 #include "inkscape.h"
54 #include "conn-avoid-ref.h"
57 #include "select-toolbar.h"
58 #include "gradient-toolbar.h"
60 #include "connector-context.h"
61 #include "sp-rect.h"
62 #include "sp-star.h"
63 #include "sp-spiral.h"
64 #include "sp-ellipse.h"
65 #include "sp-text.h"
66 #include "sp-flowtext.h"
67 #include "style.h"
68 #include "selection.h"
69 #include "document-private.h"
70 #include "desktop-style.h"
71 #include "../libnrtype/font-lister.h"
73 #include "mod360.h"
75 #include "toolbox.h"
77 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
78 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
80 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
81 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
82 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
83 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
84 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
85 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
86 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
87 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
88 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
89 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
90 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
91 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
92 static GtkWidget *sp_text_toolbox_new (SPDesktop *desktop);
95 static struct {
96     gchar const *type_name;
97     gchar const *data_name;
98     sp_verb_t verb;
99     sp_verb_t doubleclick_verb;
100 } const tools[] = {
101     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
102     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
103     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
104     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
105     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
106     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
107     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
108     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
109     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
110     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
111     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
112     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
113     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
114     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
115     { NULL, NULL, 0, 0 }
116 };
118 static struct {
119     gchar const *type_name;
120     gchar const *data_name;
121     GtkWidget *(*create_func)(SPDesktop *desktop);
122 } const aux_toolboxes[] = {
123     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
124     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
125     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
126     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
127     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
128     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
129     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
130     { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
131     { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
132     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
133     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
134     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
135     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
136     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
137     { NULL, NULL, NULL }
138 };
140 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
142 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
143 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
145 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
146 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
148 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
149 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
151 /* Global text entry widgets necessary for update */
152 /* GtkWidget *dropper_rgb_entry, 
153           *dropper_opacity_entry ; */
154 // should be made a private member once this is converted to class
156 static void delete_connection(GObject *obj, sigc::connection *connection) {
157     connection->disconnect();
158     delete connection;
161 static GtkWidget *
162 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
163                       GtkTooltips *tt, gchar const *tip)
165     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
166     gtk_widget_show(b);
167     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
168     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
170     return b;
173 GtkWidget *
174 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
175                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
176                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
178     SPAction *action = verb->get_action(view);
179     if (!action) return NULL;
181     SPAction *doubleclick_action;
182     if (doubleclick_verb)
183         doubleclick_action = doubleclick_verb->get_action(view);
184     else
185         doubleclick_action = NULL;
187     /* fixme: Handle sensitive/unsensitive */
188     /* fixme: Implement sp_button_new_from_action */
189     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
190     gtk_widget_show(b);
191     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
193     return b;
196 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
197                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
199     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
202 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
203                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
205     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
208 GtkWidget *
209 sp_tool_toolbox_new()
211     GtkTooltips *tt = gtk_tooltips_new();
212     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
214     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
215     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
217     gtk_widget_set_sensitive(tb, FALSE);
219     GtkWidget *hb = gtk_handle_box_new();
220     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
221     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
222     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
224     gtk_container_add(GTK_CONTAINER(hb), tb);
225     gtk_widget_show(GTK_WIDGET(tb));
227     sigc::connection* conn = new sigc::connection;
228     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
230     return hb;
233 static void
234 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
236     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
237     gtk_widget_queue_resize(child);
240 static void
241 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
243     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
244     gtk_widget_queue_resize(child);
247 GtkWidget *
248 sp_aux_toolbox_new()
250     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
252     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
253     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
254     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
255     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
256     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
258     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
259     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
261     gtk_widget_set_sensitive(tb, FALSE);
263     GtkWidget *hb = gtk_handle_box_new();
264     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
265     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
266     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
268     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
269     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
271     gtk_container_add(GTK_CONTAINER(hb), tb);
272     gtk_widget_show(GTK_WIDGET(tb));
274     sigc::connection* conn = new sigc::connection;
275     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
277     return hb;
280 //####################################
281 //# Commands Bar
282 //####################################
284 GtkWidget *
285 sp_commands_toolbox_new()
287     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
289     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
290     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
291     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
292     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
293     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
295     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
296     gtk_widget_set_sensitive(tb, FALSE);
298     GtkWidget *hb = gtk_handle_box_new();
299     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
300     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
301     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
303     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
304     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
306     gtk_container_add(GTK_CONTAINER(hb), tb);
307     gtk_widget_show(GTK_WIDGET(tb));
309     sigc::connection* conn = new sigc::connection;
310     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
312     return hb;
316 //####################################
317 //# node editing callbacks
318 //####################################
320 void
321 sp_node_path_edit_add(void)
323     sp_node_selected_add_node();
326 void
327 sp_node_path_edit_delete(void)
329     sp_node_selected_delete();
332 void
333 sp_node_path_edit_delete_segment(void)
335     sp_node_selected_delete_segment();
338 void
339 sp_node_path_edit_break(void)
341     sp_node_selected_break();
344 void
345 sp_node_path_edit_join(void)
347     sp_node_selected_join();
350 void
351 sp_node_path_edit_join_segment(void)
353     sp_node_selected_join_segment();
356 void
357 sp_node_path_edit_toline(void)
359     sp_node_selected_set_line_type(NR_LINETO);
362 void
363 sp_node_path_edit_tocurve(void)
365     sp_node_selected_set_line_type(NR_CURVETO);
368 void
369 sp_node_path_edit_cusp(void)
371     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
374 void
375 sp_node_path_edit_smooth(void)
377     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
380 void
381 sp_node_path_edit_symmetrical(void)
383     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
386 static void toggle_show_handles (GtkWidget *button, gpointer data) {
387     bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
388     prefs_set_int_attribute ("tools.nodes", "show_handles",  show ? 1 : 0);
389     sp_nodepath_show_handles(show);
392 //################################
393 //##    Node Editing Toolbox    ##
394 //################################
396 static GtkWidget *
397 sp_node_toolbox_new(SPDesktop *desktop)
399     Inkscape::UI::View::View *view = desktop;
401     GtkTooltips *tt = gtk_tooltips_new();
402     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
404     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
406     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
407         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
408     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
409         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
411     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
413     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
414         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
415     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
416         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
418     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
419         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
421     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
422         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
424     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
426     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
427         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
429     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
430         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
432     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
433         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
435     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
437     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
438         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
440     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
441         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
443     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
445     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
447     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
449     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
451     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
452     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
454     {
455     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
456                                               SP_BUTTON_TYPE_TOGGLE,
457                                               NULL,
458                                               "nodes_show_handles",
459                                               _("Show the Bezier handles of selected nodes"),
460                                               tt);
461     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
462     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
463     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
464     }
466     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
467     gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
469     gtk_widget_show_all(tb);
471     return tb;
473 } // end of sp_node_toolbox_new()
476 //########################
477 //##    Zoom Toolbox    ##
478 //########################
480 static GtkWidget *
481 sp_zoom_toolbox_new(SPDesktop *desktop)
483     Inkscape::UI::View::View *view=desktop;
485     GtkTooltips *tt = gtk_tooltips_new();
486     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
488     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
489                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
491     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_IN), view, tt);
493     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_OUT), view, tt);
495     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
497     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
499     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
501     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
503     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE_WIDTH), view, tt);
505     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
507     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PREV), view, tt);
509     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_NEXT), view, tt);
511     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
513     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_1), view, tt);
515     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_2), view, tt);
517     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_2_1), view, tt);
519     gtk_widget_show_all(tb);
521     return tb;
523 } // end of sp_zoom_toolbox_new()
525 void
526 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
528     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")));
532 void
533 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
535     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")));
538 void
539 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
541     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")));
544 static void
545 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
547     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
548     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
550     if (old_desktop) {
551         GList *children, *iter;
553         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
554         for ( iter = children ; iter ; iter = iter->next ) {
555             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
556         }
557         g_list_free(children);
558     }
560     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
562     if (desktop) {
563         gtk_widget_set_sensitive(toolbox, TRUE);
564         setup_func(toolbox, desktop);
565         update_func(desktop, desktop->event_context, toolbox);
566         *conn = desktop->connectEventContextChanged 
567             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
568     } else {
569         gtk_widget_set_sensitive(toolbox, FALSE);
570     }
572 } // end of toolbox_set_desktop()
575 static void
576 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
578     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
579     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
580     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
582     for (int i = 0 ; tools[i].type_name ; i++ ) {
583         GtkWidget *button =
584             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
585                                                               SP_BUTTON_TYPE_TOGGLE,
586                                                               Inkscape::Verb::get(tools[i].verb),
587                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
588                                                               desktop,
589                                                               tooltips );
591         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
592                            (gpointer)button );
593     }
597 static void
598 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
600     gchar const *const tname = ( eventcontext
601                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
602                                  : NULL );
603     for (int i = 0 ; tools[i].type_name ; i++ ) {
604         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
605         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
606     }
609 static void
610 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
612     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
614     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
615         GtkWidget *sub_toolbox;
616         if (aux_toolboxes[i].create_func == NULL)
617             sub_toolbox = sp_empty_toolbox_new(desktop);
618         else
619             sub_toolbox = aux_toolboxes[i].create_func(desktop);
621         gtk_size_group_add_widget( grouper, sub_toolbox );
623         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
624         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
625     }
626     g_object_unref( G_OBJECT(grouper) );
629 static void
630 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
632     gchar const *tname = ( eventcontext
633                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
634                            : NULL );
635     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
636         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
637         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
638             gtk_widget_show_all(sub_toolbox);
639             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
640         } else {
641             gtk_widget_hide(sub_toolbox);
642         }
643     }
646 static void
647 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
649     Inkscape::UI::View::View *view = desktop;
651     GtkTooltips *tt = gtk_tooltips_new();
652     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
654     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
655     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
657     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
658     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
659     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
660     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
662     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
664     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
665     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
667     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
669     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
670     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
672     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
674     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
675     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
676     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
678     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
680     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
681     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
682     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
684     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
686     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
687     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
688     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
690     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
692     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
693     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
695     // disabled until we have icons for them:
697     //find
699     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
700     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
702     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
704     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
705     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
706     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
707     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
709     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
711     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
712     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
714     gtk_widget_show_all(tb);
716     gtk_container_add(GTK_CONTAINER(toolbox), tb);
719 static void
720 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
724 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
726     gtk_widget_show(toolbox_toplevel);
727     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
729     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
730     if (!shown_toolbox) {
731         return;
732     }
733     gtk_widget_show(toolbox);
735     // need to show the spacer, or the padding will be off
736     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
737     gtk_widget_show(spacer);
739     gtk_widget_show_all(shown_toolbox);
742 void
743 aux_toolbox_space(GtkWidget *tb, gint space)
745     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
748 static GtkWidget *
749 sp_empty_toolbox_new(SPDesktop *desktop)
751     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
752     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
753     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
755     gtk_widget_show_all(tbl);
756     sp_set_font_size_smaller (tbl);
758     return tbl;
761 // helper UI functions
763 GtkWidget *
764 sp_tb_spinbutton(
765     gchar *label, gchar const *tooltip,
766     gchar const *path, gchar const *data, gdouble def,
767     GtkWidget *us,
768     GtkWidget *tbl,
769     gboolean altx, gchar const *altx_mark,
770     gdouble lower, gdouble upper, gdouble step, gdouble page,
771     void (*callback)(GtkAdjustment *, GtkWidget *),
772     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
774     GtkTooltips *tt = gtk_tooltips_new();
776     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
778     GtkWidget *l = gtk_label_new(label);
779     gtk_widget_show(l);
780     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
781     gtk_container_add(GTK_CONTAINER(hb), l);
783     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
784                                       lower, upper, step, page, page);
785     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
786     if (us)
787         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
789     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
790     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
791     if (altx)
792         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
793     gtk_widget_set_size_request(sb, 
794                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
795                                 AUX_SPINBUTTON_HEIGHT);
796     gtk_widget_show(sb);
797     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
798     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
799     gtk_container_add(GTK_CONTAINER(hb), sb);
800     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
802     return hb;
805 #define MODE_LABEL_WIDTH 70
807 //########################
808 //##       Star         ##
809 //########################
811 static void
812 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
814     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
816     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
817         // do not remember prefs if this call is initiated by an undo change, because undoing object
818         // creation sets bogus values to its attributes before it is deleted
819         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
820     }
822     // quit if run by the attr_changed listener
823     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
824         return;
825     }
827     // in turn, prevent listener from responding
828     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
830     bool modmade = false;
832     Inkscape::Selection *selection = sp_desktop_selection(desktop);
833     GSList const *items = selection->itemList();
834     for (; items != NULL; items = items->next) {
835         if (SP_IS_STAR((SPItem *) items->data)) {
836             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
837             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
838             sp_repr_set_svg_double(repr, "sodipodi:arg2",
839                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
840                                     + M_PI / (gint)adj->value));
841             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
842             modmade = true;
843         }
844     }
845     if (modmade)  sp_document_done(sp_desktop_document(desktop));
847     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
849     spinbutton_defocus(GTK_OBJECT(tbl));
852 static void
853 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
855     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
857     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
858         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
859     }
861     // quit if run by the attr_changed listener
862     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
863         return;
864     }
866     // in turn, prevent listener from responding
867     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
869     bool modmade = false;
870     Inkscape::Selection *selection = sp_desktop_selection(desktop);
871     GSList const *items = selection->itemList();
872     for (; items != NULL; items = items->next) {
873         if (SP_IS_STAR((SPItem *) items->data)) {
874             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
876             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
877             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
878             if (r2 < r1) {
879                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
880             } else {
881                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
882             }
884             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
885             modmade = true;
886         }
887     }
889     if (modmade) sp_document_done(sp_desktop_document(desktop));
891     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
893     spinbutton_defocus(GTK_OBJECT(tbl));
896 static void
897 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
899     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
901     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
902         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
903             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
904         } else {
905             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
906         }
907     }
909     // quit if run by the attr_changed listener
910     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
911         return;
912     }
914     // in turn, prevent listener from responding
915     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
917     Inkscape::Selection *selection = sp_desktop_selection(desktop);
918     GSList const *items = selection->itemList();
919     GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
920     bool modmade = false;
921     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
922         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
923         for (; items != NULL; items = items->next) {
924             if (SP_IS_STAR((SPItem *) items->data)) {
925                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
926                 repr->setAttribute("inkscape:flatsided", "true");
927                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
928                 modmade = true;
929             }
930         }
931     } else {
932         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
933         for (; items != NULL; items = items->next) {
934             if (SP_IS_STAR((SPItem *) items->data)) {
935                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
936                 repr->setAttribute("inkscape:flatsided", "false");
937                 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
938                 modmade = true;
939             }
940         }
941     }
942     if (modmade) sp_document_done(sp_desktop_document(desktop));
944     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
946     spinbutton_defocus(GTK_OBJECT(tbl));
949 static void
950 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
952     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
954     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
955         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
956     }
958     // quit if run by the attr_changed listener
959     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
960         return;
961     }
963     // in turn, prevent listener from responding
964     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
966     bool modmade = false;
968     Inkscape::Selection *selection = sp_desktop_selection(desktop);
969     GSList const *items = selection->itemList();
970     for (; items != NULL; items = items->next) {
971         if (SP_IS_STAR((SPItem *) items->data)) {
972             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
973             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
974             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
975             modmade = true;
976         }
977     }
978     if (modmade)  sp_document_done(sp_desktop_document(desktop));
980     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
982     spinbutton_defocus(GTK_OBJECT(tbl));
986 static void
987 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
989     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
991     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
992         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
993     }
995     // quit if run by the attr_changed listener
996     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
997         return;
998     }
1000     // in turn, prevent listener from responding
1001     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1003     bool modmade = false;
1005     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1006     GSList const *items = selection->itemList();
1007     for (; items != NULL; items = items->next) {
1008         if (SP_IS_STAR((SPItem *) items->data)) {
1009             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1010             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1011             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1012             modmade = true;
1013         }
1014     }
1015     if (modmade)  sp_document_done(sp_desktop_document(desktop));
1017     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1019     spinbutton_defocus(GTK_OBJECT(tbl));
1023 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1024                                        gchar const *old_value, gchar const *new_value,
1025                                        bool is_interactive, gpointer data)
1027     GtkWidget *tbl = GTK_WIDGET(data);
1029     // quit if run by the _changed callbacks
1030     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1031         return;
1032     }
1034     // in turn, prevent callbacks from responding
1035     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1037     GtkAdjustment *adj;
1039     if (!strcmp(name, "inkscape:randomized")) {
1040         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1041         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1042     } else if (!strcmp(name, "inkscape:rounded")) {
1043         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1044         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1045     } else if (!strcmp(name, "inkscape:flatsided")) {
1046         GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1047         GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1048         char const *flatsides = repr->attribute("inkscape:flatsided");
1049         if (flatsides && !strcmp(flatsides,"false" )) {
1050             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1051             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1052         } else {
1053             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1054             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1055         }
1056     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1057         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1058         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1059         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1060         if (r2 < r1) {
1061             gtk_adjustment_set_value(adj, r2/r1);
1062         } else {
1063             gtk_adjustment_set_value(adj, r1/r2);
1064         }
1065     } else if (!strcmp(name, "sodipodi:sides")) {
1066         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1067         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1068     }
1070     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1074 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1076     NULL, /* child_added */
1077     NULL, /* child_removed */
1078     star_tb_event_attr_changed,
1079     NULL, /* content_changed */
1080     NULL  /* order_changed */
1081 };
1084 /**
1085  *  \param selection Should not be NULL.
1086  */
1087 static void
1088 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1090     int n_selected = 0;
1091     Inkscape::XML::Node *repr = NULL;
1092     Inkscape::XML::Node *oldrepr = NULL;
1094     for (GSList const *items = selection->itemList();
1095          items != NULL;
1096          items = items->next)
1097     {
1098         if (SP_IS_STAR((SPItem *) items->data)) {
1099             n_selected++;
1100             repr = SP_OBJECT_REPR((SPItem *) items->data);
1101         }
1102     }
1104     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1106     if (n_selected == 0) {
1107         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1108     } else if (n_selected == 1) {
1109         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1111         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1112         if (oldrepr) { // remove old listener
1113             sp_repr_remove_listener_by_data(oldrepr, tbl);
1114             Inkscape::GC::release(oldrepr);
1115             oldrepr = 0;
1116             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1117         }
1119         if (repr) {
1120             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1121             Inkscape::GC::anchor(repr);
1122             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1123             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1124         }
1125     } else {
1126         // FIXME: implement averaging of all parameters for multiple selected stars
1127         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1128         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1129     }
1133 static void
1134 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1136     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1137     // callbacks to lump all the changes for all selected objects in one undo step
1139     GtkAdjustment *adj;
1141     // fixme: make settable in prefs!
1142     gint mag = 5;
1143     gdouble prop = 0.5;
1144     gboolean flat = FALSE;
1145     gdouble randomized = 0;
1146     gdouble rounded = 0;
1148     GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1149     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  flat);
1150     GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1151     gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1153     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1154     gtk_adjustment_set_value(adj, mag);
1155     gtk_adjustment_value_changed(adj);
1157     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1158     gtk_adjustment_set_value(adj, prop);
1159     gtk_adjustment_value_changed(adj);
1161     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1162     gtk_adjustment_set_value(adj, rounded);
1163     gtk_adjustment_value_changed(adj);
1165     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1166     gtk_adjustment_set_value(adj, randomized);
1167     gtk_adjustment_value_changed(adj);
1169     spinbutton_defocus(GTK_OBJECT(tbl));
1173 void
1174 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1176     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1177     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1178     GtkWidget *l = gtk_label_new(NULL);
1179     gtk_label_set_markup(GTK_LABEL(l), title);
1180     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1181     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1182     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1186 static GtkWidget *
1187 sp_star_toolbox_new(SPDesktop *desktop)
1189     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1191     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1192     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1194     GtkTooltips *tt = gtk_tooltips_new();
1196     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1198     gchar const *flatsidedstr = NULL;
1200     /* Flatsided checkbox */
1201     {
1202         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1203         GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1204         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1205         flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1206         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1207             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1208         else
1209             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1210         gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1211         gtk_widget_show(fscb);
1212         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1213         gtk_container_add(GTK_CONTAINER(hb), fscb);
1214         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1215         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1216     }
1218     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1220     /* Magnitude */
1221     {
1222         GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1223                                          "tools.shapes.star", "magnitude", 3,
1224                                          NULL, tbl, TRUE, "altx-star",
1225                                          3, 1024, 1, 1,
1226                                          sp_stb_magnitude_value_changed, 1, 0);
1227         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1228     }
1230     /* Spoke ratio */
1231     {
1232         GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1233                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1234                                          // Base radius is the same for the closest handle.
1235                                          _("Base radius to tip radius ratio"),
1236                                          "tools.shapes.star", "proportion", 0.5,
1237                                          NULL, tbl, FALSE, NULL,
1238                                          0.01, 1.0, 0.01, 0.1,
1239                                          sp_stb_proportion_value_changed);
1240         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1241         g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1242         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1243             gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1244         else
1245             gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1246     }
1248     /* Roundedness */
1249     {
1250         GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1251                                          "tools.shapes.star", "rounded", 0.0,
1252                                          NULL, tbl, FALSE, NULL,
1253                                          -100.0, 100.0, 0.01, 0.1,
1254                                          sp_stb_rounded_value_changed);
1255         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1256     }
1258     /* Randomization */
1259     {
1260         GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1261                                          "tools.shapes.star", "randomized", 0.0,
1262                                          NULL, tbl, FALSE, NULL,
1263                                          -10.0, 10.0, 0.001, 0.01,
1264                                          sp_stb_randomized_value_changed, 0.1, 3);
1265         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1266     }
1268     aux_toolbox_space(tbl, AUX_SPACING);
1270     /* Reset */
1271     {
1272         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1273         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1274         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1275         gtk_widget_show(b);
1276         gtk_container_add(GTK_CONTAINER(hb), b);
1277         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1278         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1279     }
1281     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1282     swatch->setWatchedTool ("tools.shapes.star", true);
1283     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1284     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1286     gtk_widget_show_all(tbl);
1287     sp_set_font_size_smaller (tbl);
1289     sigc::connection *connection = new sigc::connection(
1290         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1291         );
1292     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1294     return tbl;
1298 //########################
1299 //##       Rect         ##
1300 //########################
1302 static void 
1303 sp_rtb_sensitivize (GtkWidget *tbl)
1305     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1306     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1307     GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1309     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1310         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1311     } else {
1312         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1313     }
1317 static void
1318 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1319                           void (*setter)(SPRect *, gdouble))
1321     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1323     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1324     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1326     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1327         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1328     }
1330     // quit if run by the attr_changed listener
1331     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1332         return;
1333     }
1335     // in turn, prevent listener from responding
1336     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1338     bool modmade = false;
1339     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1340     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1341         if (SP_IS_RECT(items->data)) {
1342             if (adj->value != 0) {
1343                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1344             } else {
1345                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1346             }
1347             modmade = true;
1348         }
1349     }
1351     sp_rtb_sensitivize (tbl);
1353     if (modmade) {
1354         sp_document_done(sp_desktop_document(desktop));
1355     }
1357     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1359     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1360     spinbutton_defocus(GTK_OBJECT(tbl));
1363 static void
1364 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1366     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1369 static void
1370 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1372     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1375 static void
1376 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1378     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1381 static void
1382 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1384     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1389 static void
1390 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1392     GtkWidget *tbl = GTK_WIDGET(obj);
1394     GtkAdjustment *adj;
1396     adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1397     gtk_adjustment_set_value(adj, 0.0);
1398     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1399     gtk_adjustment_value_changed(adj);
1401     adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1402     gtk_adjustment_set_value(adj, 0.0);
1403     gtk_adjustment_value_changed(adj);
1405     sp_rtb_sensitivize (tbl);
1407     spinbutton_defocus(GTK_OBJECT(tbl));
1410 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1411                                        gchar const *old_value, gchar const *new_value,
1412                                        bool is_interactive, gpointer data)
1414     GtkWidget *tbl = GTK_WIDGET(data);
1416     // quit if run by the _changed callbacks
1417     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1418         return;
1419     }
1421     // in turn, prevent callbacks from responding
1422     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1424     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1425     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1427     SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1428     if (SP_IS_RECT(item)) {
1429         {
1430             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1431             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1432             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1433         }
1435         {
1436             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1437             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1438             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1439         }
1441         {
1442             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1443             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1444             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1445         }
1447         {
1448             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1449             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1450             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1451         }
1452     }
1454     sp_rtb_sensitivize (tbl);
1456     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1460 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1461     NULL, /* child_added */
1462     NULL, /* child_removed */
1463     rect_tb_event_attr_changed,
1464     NULL, /* content_changed */
1465     NULL  /* order_changed */
1466 };
1468 /**
1469  *  \param selection should not be NULL.
1470  */
1471 static void
1472 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1474     int n_selected = 0;
1475     Inkscape::XML::Node *repr = NULL;
1476     SPItem *item = NULL;
1477     Inkscape::XML::Node *oldrepr = NULL;
1479     for (GSList const *items = selection->itemList();
1480          items != NULL;
1481          items = items->next) {
1482         if (SP_IS_RECT((SPItem *) items->data)) {
1483             n_selected++;
1484             item = (SPItem *) items->data;
1485             repr = SP_OBJECT_REPR(item);
1486         }
1487     }
1489     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1491     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1493     if (n_selected == 0) {
1494         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1496         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1497         gtk_widget_set_sensitive(w, FALSE);
1498         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1499         gtk_widget_set_sensitive(h, FALSE);
1501     } else if (n_selected == 1) {
1502         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1503         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1505         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1506         gtk_widget_set_sensitive(w, TRUE);
1507         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1508         gtk_widget_set_sensitive(h, TRUE);
1510         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1511         if (oldrepr) { // remove old listener
1512             sp_repr_remove_listener_by_data(oldrepr, tbl);
1513             Inkscape::GC::release(oldrepr);
1514             oldrepr = 0;
1515             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1516         }
1517         if (repr) {
1518             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1519             g_object_set_data(G_OBJECT(tbl), "item", item);
1520             Inkscape::GC::anchor(repr);
1521             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1522             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1523         }
1524     } else {
1525         // FIXME: implement averaging of all parameters for multiple selected
1526         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1527         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1528         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1529     }
1533 static GtkWidget *
1534 sp_rect_toolbox_new(SPDesktop *desktop)
1536     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1538     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1539     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1541     GtkTooltips *tt = gtk_tooltips_new();
1543     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1545     // rx/ry units menu: create
1546     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1547     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1548     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1549     // fixme: add % meaning per cent of the width/height
1551     /* W */
1552     {
1553         GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1554                                          "tools.shapes.rect", "width", 0,
1555                                          us, tbl, TRUE, "altx-rect",
1556                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1557                                          sp_rtb_width_value_changed);
1558         gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1559         gtk_widget_set_sensitive(hb, FALSE);
1560         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1561     }
1563     /* H */
1564     {
1565         GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1566                                          "tools.shapes.rect", "height", 0,
1567                                          us, tbl, FALSE, NULL,
1568                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1569                                          sp_rtb_height_value_changed);
1570         gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1571         gtk_widget_set_sensitive(hb, FALSE);
1572         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1573     }
1575     /* rx */
1576     {
1577         GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1578                                          "tools.shapes.rect", "rx", 0,
1579                                          us, tbl, FALSE, NULL,
1580                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1581                                          sp_rtb_rx_value_changed);
1582         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1583     }
1585     /* ry */
1586     {
1587         GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1588                                          "tools.shapes.rect", "ry", 0,
1589                                          us, tbl, FALSE, NULL,
1590                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1591                                          sp_rtb_ry_value_changed);
1592         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1593     }
1595     // add the units menu
1596     gtk_widget_show(us);
1597     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1598     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1600     /* Reset */
1601     {
1602         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1603         GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1604         gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1605         gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1606         gtk_widget_show(b);
1607         gtk_container_add(GTK_CONTAINER(hb), b);
1608         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1609         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1610     }
1612     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1613     swatch->setWatchedTool ("tools.shapes.rect", true);
1614     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1615     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1617     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1618     sp_rtb_sensitivize (tbl);
1620     gtk_widget_show_all(tbl);
1621     sp_set_font_size_smaller (tbl);
1623     sigc::connection *connection = new sigc::connection(
1624         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1625         );
1626     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1628     return tbl;
1631 //########################
1632 //##       Spiral       ##
1633 //########################
1635 static void
1636 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1638     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1640     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1641         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1642     }
1644     // quit if run by the attr_changed listener
1645     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1646         return;
1647     }
1649     // in turn, prevent listener from responding
1650     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1652     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1654     bool modmade = false;
1655     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1656          items != NULL;
1657          items = items->next)
1658     {
1659         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1660             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1661             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1662             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1663             modmade = true;
1664         }
1665     }
1667     g_free(namespaced_name);
1669     if (modmade) {
1670         sp_document_done(sp_desktop_document(desktop));
1671     }
1673     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1675     spinbutton_defocus(GTK_OBJECT(tbl));
1678 static void
1679 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1681     sp_spl_tb_value_changed(adj, tbl, "revolution");
1684 static void
1685 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1687     sp_spl_tb_value_changed(adj, tbl, "expansion");
1690 static void
1691 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1693     sp_spl_tb_value_changed(adj, tbl, "t0");
1696 static void
1697 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1699     GtkWidget *tbl = GTK_WIDGET(obj);
1701     GtkAdjustment *adj;
1703     // fixme: make settable
1704     gdouble rev = 5;
1705     gdouble exp = 1.0;
1706     gdouble t0 = 0.0;
1708     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1709     gtk_adjustment_set_value(adj, rev);
1710     gtk_adjustment_value_changed(adj);
1712     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1713     gtk_adjustment_set_value(adj, exp);
1714     gtk_adjustment_value_changed(adj);
1716     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1717     gtk_adjustment_set_value(adj, t0);
1718     gtk_adjustment_value_changed(adj);
1720     spinbutton_defocus(GTK_OBJECT(tbl));
1724 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1725                                          gchar const *old_value, gchar const *new_value,
1726                                          bool is_interactive, gpointer data)
1728     GtkWidget *tbl = GTK_WIDGET(data);
1730     // quit if run by the _changed callbacks
1731     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1732         return;
1733     }
1735     // in turn, prevent callbacks from responding
1736     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1738     GtkAdjustment *adj;
1739     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1740     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1742     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1743     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1745     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1746     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1748     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1752 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1753     NULL, /* child_added */
1754     NULL, /* child_removed */
1755     spiral_tb_event_attr_changed,
1756     NULL, /* content_changed */
1757     NULL  /* order_changed */
1758 };
1760 static void
1761 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1763     int n_selected = 0;
1764     Inkscape::XML::Node *repr = NULL;
1765     Inkscape::XML::Node *oldrepr = NULL;
1767     for (GSList const *items = selection->itemList();
1768          items != NULL;
1769          items = items->next)
1770     {
1771         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1772             n_selected++;
1773             repr = SP_OBJECT_REPR((SPItem *) items->data);
1774         }
1775     }
1777     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1779     if (n_selected == 0) {
1780         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1781     } else if (n_selected == 1) {
1782         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1784         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1785         if (oldrepr) { // remove old listener
1786             sp_repr_remove_listener_by_data(oldrepr, tbl);
1787             Inkscape::GC::release(oldrepr);
1788             oldrepr = 0;
1789             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1790         }
1792         if (repr) {
1793             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1794             Inkscape::GC::anchor(repr);
1795             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1796             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1797         }
1798     } else {
1799         // FIXME: implement averaging of all parameters for multiple selected
1800         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1801         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1802     }
1806 static GtkWidget *
1807 sp_spiral_toolbox_new(SPDesktop *desktop)
1809     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1810     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1811     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1813     GtkTooltips *tt = gtk_tooltips_new();
1815     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1817     /* Revolution */
1818     {
1819         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1820                                          "tools.shapes.spiral", "revolution", 3.0,
1821                                          NULL, tbl, TRUE, "altx-spiral",
1822                                          0.01, 1024.0, 0.1, 1.0,
1823                                          sp_spl_tb_revolution_value_changed, 1, 2);
1824         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1825     }
1827     /* Expansion */
1828     {
1829         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1830                                          "tools.shapes.spiral", "expansion", 1.0,
1831                                          NULL, tbl, FALSE, NULL,
1832                                          0.0, 1000.0, 0.01, 1.0,
1833                                          sp_spl_tb_expansion_value_changed);
1834         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1835     }
1837     /* T0 */
1838     {
1839         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1840                                          "tools.shapes.spiral", "t0", 0.0,
1841                                          NULL, tbl, FALSE, NULL,
1842                                          0.0, 0.999, 0.01, 1.0,
1843                                          sp_spl_tb_t0_value_changed);
1844         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1845     }
1847     aux_toolbox_space(tbl, AUX_SPACING);
1849     /* Reset */
1850     {
1851         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1852         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1853         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1854         gtk_widget_show(b);
1855         gtk_container_add(GTK_CONTAINER(hb), b);
1856         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1857         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1858     }
1860     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1861     swatch->setWatchedTool ("tools.shapes.spiral", true);
1862     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1863     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1865     gtk_widget_show_all(tbl);
1866     sp_set_font_size_smaller (tbl);
1868     sigc::connection *connection = new sigc::connection(
1869         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1870         );
1871     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1873     return tbl;
1876 //########################
1877 //##     Pen/Pencil    ##
1878 //########################
1881 static GtkWidget *
1882 sp_pen_toolbox_new(SPDesktop *desktop)
1884     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1885     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1886     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1888     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1889     swatch->setWatchedTool ("tools.freehand.pen", true);
1890     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1891     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1893     gtk_widget_show_all(tbl);
1894     sp_set_font_size_smaller (tbl);
1896     return tbl;
1899 static GtkWidget *
1900 sp_pencil_toolbox_new(SPDesktop *desktop)
1902     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1903     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1904     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1906     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1907     swatch->setWatchedTool ("tools.freehand.pencil", true);
1908     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1909     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1911     gtk_widget_show_all(tbl);
1912     sp_set_font_size_smaller (tbl);
1914     return tbl;
1918 //########################
1919 //##     Calligraphy    ##
1920 //########################
1922 static void
1923 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1925     prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1926     spinbutton_defocus(GTK_OBJECT(tbl));
1929 static void
1930 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1932     prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1933     spinbutton_defocus(GTK_OBJECT(tbl));
1936 static void
1937 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1939     prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1940     spinbutton_defocus(GTK_OBJECT(tbl));
1943 static void
1944 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1946     prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1947     spinbutton_defocus(GTK_OBJECT(tbl));
1950 static void
1951 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1953     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1954     spinbutton_defocus(GTK_OBJECT(tbl));
1957 static void
1958 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1960     prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1961     spinbutton_defocus(GTK_OBJECT(tbl));
1964 static void
1965 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1967     prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1968     spinbutton_defocus(GTK_OBJECT(tbl));
1971 static void
1972 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1974     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1977 static void
1978 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1980     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1982     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1985 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
1987     // FIXME: make defaults settable via Inkscape Options
1988     struct KeyValue {
1989         char const *key;
1990         double value;
1991     } const key_values[] = {
1992         {"mass", 0.02},
1993         {"drag", 1.0},
1994         {"angle", 30.0},
1995         {"width", 15},
1996         {"thinning", 0.1},
1997         {"tremor", 0.0},
1998         {"flatness", 0.9}
1999     };
2001     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2002         KeyValue const &kv = key_values[i];
2003         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2004         gtk_adjustment_set_value(&adj, kv.value);
2005     }
2007     spinbutton_defocus(GTK_OBJECT(tbl));
2010 static GtkWidget *
2011 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2013     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2014     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2015     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2017     GtkTooltips *tt = gtk_tooltips_new();
2018     GtkWidget *calligraphy_angle;
2020     //  interval
2021     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2023     /* Width */
2024     {
2025         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2026                                          "tools.calligraphic", "width", 15,
2027                                          NULL, tbl, TRUE, "altx-calligraphy",
2028                                          1, 100, 1.0, 10.0,
2029                                          sp_ddc_width_value_changed,  0.01, 0, 100);
2030         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2031     }
2033     /* Thinning */
2034     {
2035         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)"),
2036                                          "tools.calligraphic", "thinning", 0.1,
2037                                          NULL, tbl, FALSE, NULL,
2038                                          -1.0, 1.0, 0.01, 0.1,
2039                                          sp_ddc_velthin_value_changed, 0.01, 2);
2040         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2041     }
2043     //  interval
2044     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2046     /* Angle */
2047     {
2048         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2049                                              "tools.calligraphic", "angle", 30,
2050                                              NULL, tbl, TRUE, "calligraphy-angle",
2051                                              -90.0, 90.0, 1.0, 10.0,
2052                                              sp_ddc_angle_value_changed, 1, 0);
2053         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2054     }
2056     /* Fixation */
2057     {
2058         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2059                                          "tools.calligraphic", "flatness", 0.9,
2060                                          NULL, tbl, FALSE, NULL,
2061                                          0.0, 1.0, 0.01, 0.1,
2062                                          sp_ddc_flatness_value_changed, 0.01, 2);
2063         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2064     }
2066     //  interval
2067     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2069     /* Tremor */
2070     {
2071         GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2072                                          "tools.calligraphic", "tremor", 0.0,
2073                                          NULL, tbl, FALSE, NULL,
2074                                          0.0, 1.0, 0.01, 0.1,
2075                                          sp_ddc_tremor_value_changed, 0.01, 2);
2076         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2077     }
2078     /* Mass */
2079     {
2080         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2081                                          "tools.calligraphic", "mass", 0.02,
2082                                          NULL, tbl, FALSE, NULL,
2083                                          0.0, 1.0, 0.01, 0.1,
2084                                          sp_ddc_mass_value_changed, 0.01, 2);
2085         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2086     }
2088     /* Drag */
2089     {
2090         // TRANSLATORS: "drag" means "resistance" here
2091         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2092                                          "tools.calligraphic", "drag", 1,
2093                                          NULL, tbl, FALSE, NULL,
2094                                          0.0, 1.0, 0.01, 0.1,
2095                                          sp_ddc_drag_value_changed, 0.01, 2);
2096         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2097     }
2099     //  interval
2100     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2102     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2103     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2105     /* Use Pressure button */
2106     {
2107     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2108                                                  SP_BUTTON_TYPE_TOGGLE,
2109                                                  NULL,
2110                                                  "use_pressure",
2111                                                  _("Use the pressure of the input device to alter the width of the pen"),
2112                                                  tt);
2113     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2114     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2115     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2116     }
2118     /* Use Tilt button */
2119     {
2120     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2121                                                  SP_BUTTON_TYPE_TOGGLE,
2122                                                  NULL,
2123                                                  "use_tilt",
2124                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2125                                                  tt);
2126     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2127     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2128     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2129     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2130     }
2132     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2133     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2135     /* Reset */
2136     {
2137         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2138         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2139         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2140         gtk_widget_show(b);
2141         gtk_container_add(GTK_CONTAINER(hb), b);
2142         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2143         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2144     }
2147     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2148     swatch->setWatchedTool ("tools.calligraphic", true);
2149     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2150     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2152     gtk_widget_show_all(tbl);
2153     sp_set_font_size_smaller (tbl);
2155     return tbl;
2159 //########################
2160 //##    Circle / Arc    ##
2161 //########################
2163 static void 
2164 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2166     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2167     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2169     if (v1 == 0 && v2 == 0) {
2170         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2171             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2172             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2173         }
2174     } else {
2175         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2176         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2177     }
2180 static void
2181 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2183     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2185     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2186         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2187     }
2189     // quit if run by the attr_changed listener
2190     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2191         return;
2192     }
2194     // in turn, prevent listener from responding
2195     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2197     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2199     bool modmade = false;
2200     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2201          items != NULL;
2202          items = items->next)
2203     {
2204         SPItem *item = SP_ITEM(items->data);
2206         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2208             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2209             SPArc *arc = SP_ARC(item);
2211             if (!strcmp(value_name, "start"))
2212                 ge->start = (adj->value * M_PI)/ 180;
2213             else
2214                 ge->end = (adj->value * M_PI)/ 180;
2216             sp_genericellipse_normalize(ge);
2217             ((SPObject *)arc)->updateRepr();
2218             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2220             modmade = true;
2221         }
2222     }
2224     g_free(namespaced_name);
2226     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2228     sp_arctb_sensitivize (tbl, adj->value, other->value);
2230     if (modmade) {
2231         sp_document_maybe_done(sp_desktop_document(desktop), value_name);
2232     }
2234     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2235     spinbutton_defocus(GTK_OBJECT(tbl));
2237     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2241 static void
2242 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2244     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2247 static void
2248 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2250     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2253 static void
2254 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2256     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2258     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2259         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2260             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2261         } else {
2262             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2263         }
2264     }
2266     // quit if run by the attr_changed listener
2267     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2268         return;
2269     }
2271     // in turn, prevent listener from responding
2272     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2274     bool modmade = false;
2276     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2277         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2278              items != NULL;
2279              items = items->next)
2280         {
2281             if (SP_IS_ARC((SPItem *) items->data)) {
2282                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2283                 repr->setAttribute("sodipodi:open", "true");
2284                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2285                 modmade = true;
2286             }
2287         }
2288     } else {
2289         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2290              items != NULL;
2291              items = items->next)
2292         {
2293             if (SP_IS_ARC((SPItem *) items->data))    {
2294                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2295                 repr->setAttribute("sodipodi:open", NULL);
2296                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2297                 modmade = true;
2298             }
2299         }
2300     }
2302     if (modmade) {
2303         sp_document_done(sp_desktop_document(desktop));
2304     }
2306     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2308     spinbutton_defocus(GTK_OBJECT(tbl));
2311 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2313     GtkWidget *tbl = GTK_WIDGET(obj);
2315     GtkAdjustment *adj;
2316     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2317     gtk_adjustment_set_value(adj, 0.0);
2318     gtk_adjustment_value_changed(adj);
2320     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2321     gtk_adjustment_set_value(adj, 0.0);
2322     gtk_adjustment_value_changed(adj);
2324     spinbutton_defocus(GTK_OBJECT(tbl));
2327 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2328                                       gchar const *old_value, gchar const *new_value,
2329                                       bool is_interactive, gpointer data)
2331     GtkWidget *tbl = GTK_WIDGET(data);
2333     // quit if run by the _changed callbacks
2334     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2335         return;
2336     }
2338     // in turn, prevent callbacks from responding
2339     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2341     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2342     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2344     GtkAdjustment *adj1,*adj2;
2345     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2346     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2347     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2348     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2350     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2352     char const *openstr = NULL;
2353     openstr = repr->attribute("sodipodi:open");
2354     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2356     if (openstr) {
2357         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2358     } else {
2359         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2360     }
2362     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2365 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2366     NULL, /* child_added */
2367     NULL, /* child_removed */
2368     arc_tb_event_attr_changed,
2369     NULL, /* content_changed */
2370     NULL  /* order_changed */
2371 };
2374 static void
2375 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2377     int n_selected = 0;
2378     Inkscape::XML::Node *repr = NULL;
2379     Inkscape::XML::Node *oldrepr = NULL;
2381     for (GSList const *items = selection->itemList();
2382          items != NULL;
2383          items = items->next)
2384     {
2385         if (SP_IS_ARC((SPItem *) items->data)) {
2386             n_selected++;
2387             repr = SP_OBJECT_REPR((SPItem *) items->data);
2388         }
2389     }
2391     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2393     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2394     if (n_selected == 0) {
2395         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2396     } else if (n_selected == 1) {
2397         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2398         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2400         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2402         if (oldrepr) { // remove old listener
2403             sp_repr_remove_listener_by_data(oldrepr, tbl);
2404             Inkscape::GC::release(oldrepr);
2405             oldrepr = 0;
2406             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2407         }
2409         if (repr) {
2410             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2411             Inkscape::GC::anchor(repr);
2412             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2413             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2414         }
2415     } else {
2416         // FIXME: implement averaging of all parameters for multiple selected
2417         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2418         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2419         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2420     }
2424 static GtkWidget *
2425 sp_arc_toolbox_new(SPDesktop *desktop)
2427     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2429     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2430     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2432     GtkTooltips *tt = gtk_tooltips_new();
2434     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2436     /* Start */
2437     {
2438         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2439                                          "tools.shapes.arc", "start", 0.0,
2440                                          NULL, tbl, TRUE, "altx-arc",
2441                                          -360.0, 360.0, 1.0, 10.0,
2442                                          sp_arctb_start_value_changed);
2443         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2444     }
2446     /* End */
2447     {
2448         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2449                                          "tools.shapes.arc", "end", 0.0,
2450                                          NULL, tbl, FALSE, NULL,
2451                                          -360.0, 360.0, 1.0, 10.0,
2452                                          sp_arctb_end_value_changed);
2453         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2454     }
2456     /* Segments / Pie checkbox */
2457     {
2458         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2459         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2460         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2462         gchar const *openstr = NULL;
2463         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2464         if (!openstr || (openstr && !strcmp(openstr, "false")))
2465             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2466         else
2467             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2469         gtk_widget_show(fscb);
2470         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2471         gtk_container_add(GTK_CONTAINER(hb), fscb);
2472         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2473         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2474     }
2476     /* Make Whole */
2477     {
2478         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2479         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2480         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2481         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2482         gtk_widget_show(b);
2483         gtk_container_add(GTK_CONTAINER(hb), b);
2484         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2485         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2486     }
2488     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2489     // sensitivize make whole and open checkbox
2490     {
2491         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2492         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2493         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2494     }
2496     sigc::connection *connection = new sigc::connection(
2497         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2498         );
2499     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2501     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2502     swatch->setWatchedTool ("tools.shapes.arc", true);
2503     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2504     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2506     gtk_widget_show_all(tbl);
2507     sp_set_font_size_smaller (tbl);
2509     return tbl;
2515 // toggle button callbacks and updaters
2517 //########################
2518 //##      Dropper       ##
2519 //########################
2521 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2522     prefs_set_int_attribute ("tools.dropper", "pick", 
2523         // 0 and 1 are backwards here because of pref
2524         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2528 /**
2529  * Copy the current saved desktop color to the clipboard as full hex + alpha
2530  * color representation. This is useful for passing values between various 
2531  * input boxes, or directly to xml.
2532  */
2533 /* static void
2534 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2536     GtkWidget *tbl = GTK_WIDGET(obj);
2537     
2538     SPDesktop *desktop = 
2539         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2541    
2542     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2543 }*/
2546 /**
2547  * Copies currently saved desktop color to the clipboard as a hex value. This 
2548  * is useful for editing webpages and needing a value quickly for web
2549  * colors.
2550  * 
2551  * TODO: When the toggle of the dropper is set to not mix color against 
2552  *       page background, this still just gets the color of the page and 
2553  *       doesn't get the actual mixed against background which is needed 
2554  *       for the hex value ppl. want for web pages, etc.
2555  */
2557 /* static void
2558 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2560     GtkWidget *tbl = GTK_WIDGET(obj);
2561     
2562     SPDesktop *desktop = 
2563         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2564     
2565     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2566 }*/
2569 /**
2570  * Sets the input boxes with the changed color and opacity. This is used as a 
2571  * callback for style changing.
2572  */
2573 /* static bool
2574 sp_style_changed (const SPCSSAttr *css, gpointer data)
2576     // GrDrag *drag = (GrDrag *) data;
2577     
2578     // set fill of text entry box
2579     if (css->attribute("fill"))
2580         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2581             css->attribute("fill")); 
2583     // set opacity of text entry box
2584     if (css->attribute("fill-opacity"))
2585         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2586             css->attribute("fill-opacity")); 
2587     
2588     // set fill of text entry box
2589     if (css->attribute("stroke"))
2590         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2591             css->attribute("stroke")); 
2593     // set opacity of text entry box
2594     if (css->attribute("stroke-opacity"))
2595         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2596             css->attribute("stroke-opacity"));
2597     return false;
2600 */
2603 /**
2604  * Dropper auxiliary toolbar construction and setup.
2605  *
2606  * TODO: Would like to add swatch of current color.
2607  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2608  *       can drag and drop places. Will provide a nice mixing palette.
2609  */
2610 static GtkWidget *
2611 sp_dropper_toolbox_new(SPDesktop *desktop)
2613     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2615     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2616     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2618     GtkTooltips *tt = gtk_tooltips_new();
2620     
2621     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2622                        AUX_BETWEEN_BUTTON_GROUPS);
2623     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2626     
2627     /* RGB Input Field */
2628  /*   {
2629         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2630         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2631         gtk_widget_show (dropper_rgba_label);
2632         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2633         
2634         dropper_rgb_entry = gtk_entry_new ();
2635         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2636         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2637         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2638         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2639                          _("Hexidecimal representation of last selected "
2640                            "color"), 
2641                          NULL);
2642         gtk_widget_show (dropper_rgb_entry);
2643         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2644         
2645         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2646                            AUX_BETWEEN_BUTTON_GROUPS);
2647     } */
2648     
2649     /* Opacity Input Field */
2650 /*    {
2651         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2652         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2653         gtk_widget_show (dropper_opacity_label);
2654         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2655         
2656         dropper_opacity_entry = gtk_entry_new ();
2657         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2658         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2659         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2660         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2661                          _("Opacity of last selected color"), 
2662                          NULL);
2663         gtk_widget_show (dropper_opacity_entry);
2664         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2665         
2666         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2667                            AUX_BETWEEN_BUTTON_GROUPS);
2668     } */
2669     
2670     
2671     /* Copy to Clipboard */
2672 /*    {
2673         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2674         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2675         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2676                                       "RGB + Alpha (RGBA) to "
2677                                       "clipboard"), 
2678                              NULL);
2679         gtk_widget_show(b);
2680         gtk_container_add(GTK_CONTAINER(hb), b);
2681         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2682             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2683         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2684                            AUX_BETWEEN_BUTTON_GROUPS);
2685     } */
2688     /* Copy to Clipboard as HEX */
2689 /*    {
2690         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2691         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2692         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2693                                       "hexidecimal RGB without alpha " 
2694                                       "to clipboard"), NULL);
2695         gtk_widget_show(b);
2696         gtk_container_add(GTK_CONTAINER(hb), b);
2697         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2698             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2699         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2700                            AUX_BETWEEN_BUTTON_GROUPS);
2701     } */
2702     
2703     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2704     
2705     {
2706         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2707         
2708         GtkWidget *button = 
2709             sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2710                                      SP_BUTTON_TYPE_TOGGLE,
2711                                      NULL,
2712                                      "pick_color",
2713                                      _("When pressed, picks visible color "
2714                                        "without alpha and when not pressed, "
2715                                        "picks color including its "
2716                                        "alpha"),
2717                                      tt);
2719         gtk_widget_show(button);
2720         gtk_container_add (GTK_CONTAINER (hb), button);
2722         g_signal_connect_after (G_OBJECT (button), "clicked", 
2723                                 G_CALLBACK (toggle_dropper_color_pick), NULL);
2724         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2725                                       !prefs_get_int_attribute ("tools.dropper", 
2726                                                                "pick", 0));
2727         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2728                    AUX_BETWEEN_BUTTON_GROUPS);
2729     }
2730    
2731     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2732     
2734     // where new gtkmm stuff should go
2735     
2736     gtk_widget_show_all(tbl);
2737     sp_set_font_size_smaller (tbl);
2739     /*
2740     sigc::connection *connection = new sigc::connection(
2741         desktop->connectSetStyle(
2742             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2743                        desktop)) ); 
2744     
2745     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2746                      connection); */
2747     
2748     return tbl;
2752 //########################
2753 //##    Text Toolbox    ##
2754 //########################
2755 /*
2756 static void
2757 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2759     //Call back for letter sizing spinbutton
2762 static void
2763 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2765     //Call back for line height spinbutton
2768 static void
2769 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2771     //Call back for horizontal kerning spinbutton
2774 static void
2775 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2777     //Call back for vertical kerning spinbutton
2780 static void
2781 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2783     //Call back for letter rotation spinbutton
2784 }*/
2786 static void
2787 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2789     GtkWidget *cbox = GTK_WIDGET(g_object_get_data (G_OBJECT(tbl), "combo-box-family"));
2790     Inkscape::XML::Node *repr = 0;
2791     SPStyle *style = 0; 
2792     bool multiple = false;
2794     // create temporary style
2795     SPStyle *query = sp_style_new ();
2796     // query style from desktop into it. This returns a result flag and fills query with the style of subselection, if any, or selection
2797     int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); 
2798     int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); 
2799     int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2801     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2802     if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2803     {
2804         repr = inkscape_get_repr (INKSCAPE, "tools.text");
2805         if (repr)
2806         {
2807             sp_style_read_from_repr (query, repr);
2808         }
2809         else
2810         {
2811             return;
2812         }
2813     }
2815 #if 0
2816     // FIXME: process result_family/style == QUERY_STYLE_MULTIPLE_DIFFERENT by showing "Many" in the lists
2817     font_instance *font = (font_factory::Default())->Face ( query->text->font_family.value, font_style_to_pos(*query) );
2818     if (font)
2819     {
2820         // the font is oversized, so we need to pass the true size separately
2821         sp_font_selector_set_font (SP_FONT_SELECTOR (fontsel), font, query->font_size.computed);
2822         sp_font_preview_set_font (SP_FONT_PREVIEW (preview), font, SP_FONT_SELECTOR(fontsel));
2823                                                 font->Unref();
2824                                                 font=NULL;
2825     }
2826 #endif
2828     if (result_numbers > 1)
2829     {
2830         g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2831         gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), -1); 
2832         g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2833         return;
2834     }
2836     Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2837     gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), gtk_tree_path_get_indices (path.gobj())[0]);
2840 static void
2841 sp_text_toolbox_family_changed (GtkComboBox *cbox,
2842                                 GtkWidget   *tbl) 
2844     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2846     if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
2848     SPCSSAttr *css = sp_repr_css_attr_new (); 
2849     sp_repr_css_set_property (css, "font-family", gtk_combo_box_get_active_text (cbox));
2850     sp_desktop_set_style(desktop, css, true, true);
2851     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2852     sp_repr_css_attr_unref (css);
2855 #if 0
2856 static void  cell_data_func  (GtkCellLayout     *cell_layout,
2857                               GtkCellRenderer   *cell,
2858                               GtkTreeModel      *tree_model,
2859                               GtkTreeIter       *iter,
2860                               gpointer           data)
2862     char *text; 
2863     gtk_tree_model_get (tree_model, iter, 0, &text, -1); 
2864     g_object_set (G_OBJECT (cell), "family", text, NULL);
2866 #endif
2868 static GtkWidget*
2869 sp_text_toolbox_new (SPDesktop *desktop)
2871     GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
2873 #if 0
2874     GtkWidget   *us = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "units"));
2875     GtkTooltips *tt = gtk_tooltips_new();
2876     GtkWidget   *group;
2877 #endif
2879     //Font Family
2880     GtkWidget *cbox = gtk_combo_box_entry_new_text ();
2881     Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
2882     gtk_cell_layout_clear (GTK_CELL_LAYOUT (cbox));
2883     GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
2884     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), cell, FALSE);
2885     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), cell, "text", 0, NULL);
2887 #if 0
2888     gtk_cell_layout_set_cell_data_func
2889             (GTK_CELL_LAYOUT (cbox),
2890              cell, 
2891              GtkCellLayoutDataFunc (cell_data_func),
2892              tbl, 
2893              NULL); 
2894 #endif
2896     gtk_combo_box_set_model (GTK_COMBO_BOX (cbox), GTK_TREE_MODEL (Glib::unwrap(store)));
2898     gtk_widget_set_size_request (cbox, 250, -1);
2899     aux_toolbox_space (tbl, 1);
2900     gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2901     g_object_set_data (G_OBJECT (tbl), "combo-box-family", cbox);
2902     g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
2904 #if 0
2905     //Font Style
2906     GtkWidget *cbox = gtk_combo_box_new_text ();
2907     gtk_widget_set_size_request (cbox, 144, -1);
2908     aux_toolbox_space (tbl, 1);
2909     gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2910     g_object_set_data (G_OBJECT (tbl), "combo-box-style", cbox);
2911 #endif
2913     sigc::connection *connection =
2914     new sigc::connection(sp_desktop_selection(desktop)->connectChanged (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
2915     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2917 #if 0
2918     //Font Size
2919     {
2920             GtkWidget *c = gtk_combo_new ();
2921             gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2922             gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2923             gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2924             gtk_widget_set_size_request (c, 64, -1);
2925             aux_toolbox_space(tbl, 1);
2926             gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2927     }
2929     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2930     //Bold
2931     {
2932             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2933             GtkWidget *button = gtk_toggle_button_new ();
2934             gtk_container_add (GTK_CONTAINER (button), px);
2935             gtk_widget_show(button);
2936             gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
2937             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2938             gtk_widget_set_sensitive(button, TRUE);
2939             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2940     }
2943         //Italic
2944         {
2945             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2946             GtkWidget *button = gtk_toggle_button_new ();
2947             gtk_container_add (GTK_CONTAINER (button), px);
2948             gtk_widget_show(button);
2949             gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
2950             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2951             gtk_widget_set_sensitive(button, TRUE);
2952             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2953         }
2955         //Underline
2956         {
2957             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2958             GtkWidget *button = gtk_toggle_button_new ();
2959             gtk_container_add (GTK_CONTAINER (button), px);
2960             gtk_widget_show(button);
2961             gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
2962             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2963             gtk_widget_set_sensitive(button, FALSE);
2964             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2965         }
2967         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2968         // align left
2969         {
2970             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2971             GtkWidget *b = group = gtk_radio_button_new (NULL);
2972                 gtk_container_add (GTK_CONTAINER (b), px);
2973             gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
2974             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2975             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2976             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2977         }
2979         // align center
2980         {
2981             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2982             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2983                 gtk_container_add (GTK_CONTAINER (b), px);
2984             // TRANSLATORS: `Center' here is a verb.
2985             gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
2986                 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2987             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2988             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2989         }
2991         // align right
2992         {
2993             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2994             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2995                 gtk_container_add (GTK_CONTAINER (b), px);
2996             gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
2997             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2998             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2999             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3000         }
3002         // full justification
3003         {
3004             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3005             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3006                 gtk_container_add (GTK_CONTAINER (b), px);
3007             gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
3008             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3009             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3010             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3011         }
3012         
3013                 
3014         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3015                 
3016         // horizontal
3017         {
3018         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3019         GtkWidget *b = group = gtk_radio_button_new (NULL);
3020                 gtk_container_add (GTK_CONTAINER (b), px);
3021         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3022         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3023         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3024         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3025         }
3027         // vertical
3028         {
3029         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3030         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3031                 gtk_container_add (GTK_CONTAINER (b), px);
3032         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3033         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3034         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3035         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3036         }
3038         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3040         // letter spacing
3041     {
3042         {
3043         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3044         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3045         gtk_container_add (GTK_CONTAINER (hb), image);
3046         gtk_widget_show(image);
3047         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3048         }
3049     
3050         {
3051             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3052                                              "tools.text", "letter_spacing", 0.0,
3053                                              us, tbl, FALSE, NULL,
3054                                              -1000.0, 1000.0, 0.1, 0.1,
3055                                              sp_text_letter_changed, 0.1, 1);
3056             gtk_widget_set_size_request (hb, 45, 6);
3057             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3058         }
3059     }
3061         // line spacing
3062     {
3063         {
3064         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3065         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3066         gtk_container_add (GTK_CONTAINER (hb), image);
3067         gtk_widget_show(image);
3068         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3069         }
3070     
3071         {
3072             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3073                                              "tools.text", "line_spacing", 0,
3074                                              us, tbl, FALSE, NULL,
3075                                              -1000.0, 1000.0, 0.1, 0.1,
3076                                              sp_text_line_changed, 0.1, 1);
3077             gtk_widget_set_size_request (hb, 45, 0);
3078             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3079         }
3080     }
3083     // horizontal kerning/vertical kerning units menu: create
3084     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3085     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3086     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3088     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3090     // horizontal kerning
3091     {
3092         {
3093         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3094         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3095         gtk_container_add (GTK_CONTAINER (hb), image);
3096         gtk_widget_show(image);
3097         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3098         }
3100         {
3101             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3102                                              "tools.text", "horizontal_kerning", 0,
3103                                              us, tbl, FALSE, NULL,
3104                                              -100.00, 100.00, 0.01, 0.1,
3105                                              sp_text_horiz_kern_changed);
3106             gtk_widget_set_size_request (hb, 45, 0);
3107             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3108         }
3109     }
3111     // vertical kerning
3112     {
3113         {
3114         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3115         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3116         gtk_container_add (GTK_CONTAINER (hb), image);
3117         gtk_widget_show(image);
3118         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3119         }
3120     
3121         {
3122             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3123                                              "tools.text", "vertical_kerning", 0,
3124                                              us, tbl, FALSE, NULL,
3125                                              -100.00, 100.00, 0.01, 0.1,
3126                                              sp_text_vert_kern_changed);
3127             gtk_widget_set_size_request (hb, 45, 0);
3128             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3129         }
3130     }
3132     // add the units menu
3133     gtk_widget_show(us);
3134     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3135     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3136     }
3138         // letter rotation
3139     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3140     {
3141         {
3142         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3143         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3144         gtk_container_add (GTK_CONTAINER (hb), image);
3145         gtk_widget_show(image);
3146         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3147         }
3148         {
3149             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3150                                              "tools.text", "letter_rotation", 0,
3151                                              us, tbl, FALSE, NULL,
3152                                              -180.0, 180.0, 0.1, 0.1,
3153                                              sp_text_letter_rotation_changed, 0.1, 1);
3154             gtk_widget_set_size_request (hb, 45, 0);
3155             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3156         }
3157         // rotation degree label
3158         {
3159         GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3160         gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3161         }
3162     }
3163         
3164         // Remove Manual Kerns
3165         {
3166         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3167         GtkWidget *button = gtk_button_new ();
3168         gtk_container_add (GTK_CONTAINER (button), px);
3169         gtk_widget_show(button);
3170         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3171         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3172         gtk_widget_set_sensitive(button, TRUE);
3173         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3174         }
3175 #endif
3177     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
3178     swatch->setWatchedTool ("tools.text", true);
3179     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
3180     gtk_box_pack_end (GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
3181     gtk_widget_show_all (tbl);
3183     return tbl;
3185 } // end of sp_text_toolbox_new()
3188 //#########################
3189 //##  Connector Toolbox  ##
3190 //#########################
3192 static void sp_connector_path_set_avoid(void)
3194     cc_selection_set_avoid(true);
3198 static void sp_connector_path_set_ignore(void)
3200     cc_selection_set_avoid(false);
3204 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3206     // quit if run by the _changed callbacks
3207     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3208         return;
3209     }
3210         
3211     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3212             "desktop");
3213     SPDocument *doc = sp_desktop_document(desktop);
3215     if (!sp_document_get_undo_sensitive(doc))
3216     {
3217         return;
3218     }
3220     // in turn, prevent callbacks from responding
3221     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3222     
3223     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3224     
3225     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3226     SP_OBJECT(desktop->namedview)->updateRepr();
3227     
3228     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3229     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3230         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3231         NR::Matrix m = NR::identity();
3232         avoid_item_move(&m, item);
3233     }
3235     if (items) {
3236         g_slist_free(items);
3237     }
3238     
3239     sp_document_done(doc);
3241     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3242     
3243     spinbutton_defocus(GTK_OBJECT(tbl));
3247 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3248         gchar const *name, gchar const *old_value, gchar const *new_value,
3249         bool is_interactive, gpointer data)
3251     GtkWidget *tbl = GTK_WIDGET(data);
3253     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3254         return;
3255     }
3256     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3257         return;
3258     }
3260     GtkAdjustment *adj = (GtkAdjustment*)
3261             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3262     gdouble spacing = defaultConnSpacing;
3263     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3264     
3265     gtk_adjustment_set_value(adj, spacing);
3269 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3270     NULL, /* child_added */
3271     NULL, /* child_removed */
3272     connector_tb_event_attr_changed,
3273     NULL, /* content_changed */
3274     NULL  /* order_changed */
3275 };
3278 static GtkWidget *
3279 sp_connector_toolbox_new(SPDesktop *desktop)
3281     GtkTooltips *tt = gtk_tooltips_new();
3282     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3283     
3284     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3285     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3287     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3288             AUX_BETWEEN_BUTTON_GROUPS);
3290     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3291             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3292             tt, _("Make connectors avoid selected objects"));
3294     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3295             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3296             tt, _("Make connectors ignore selected objects"));
3298     //  interval
3299     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3300             AUX_BETWEEN_BUTTON_GROUPS);
3302     // Spacing spinbox
3303     {
3304         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3305                 _("The amount of space left around objects by auto-routing connectors"),
3306                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3307                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3308                 connector_spacing_changed, 1, 0);
3310         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3311                 AUX_SPACING);
3312     }
3314     gtk_widget_show_all(tbl);
3315     sp_set_font_size_smaller (tbl);
3316     
3317     // Code to watch for changes to the connector-spacing attribute in
3318     // the XML.
3319     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3320     g_assert(repr != NULL);
3321         
3322     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3323             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3324     
3325     if (oldrepr) { // remove old listener
3326         sp_repr_remove_listener_by_data(oldrepr, tbl);
3327         Inkscape::GC::release(oldrepr);
3328         oldrepr = NULL;
3329         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3330     }
3332     if (repr) {
3333         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3334         Inkscape::GC::anchor(repr);
3335         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3336         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3337     }
3338     
3339     return tbl;
3341 } // end of sp_connector_toolbox_new()
3344 /*
3345   Local Variables:
3346   mode:c++
3347   c-file-style:"stroustrup"
3348   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3349   indent-tabs-mode:nil
3350   fill-column:99
3351   End:
3352 */
3353 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :