Code

7fd927cd4d77991cbb6f3efe81ae535b6411ce52
[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 //  Inkscape::XML::Node *oldrepr = 0;
2792     SPStyle *style = 0; 
2793     bool multiple = false;
2794     const GSList *items = selection->itemList();
2796     for ( ; items ; items = items->next)
2797     {
2798         if (SP_IS_TEXT((SPItem *) items->data))
2799         {
2800             if (!style)
2801             {
2802                 repr = SP_OBJECT_REPR((SPItem *) items->data);
2803                 style = sp_style_new ();
2804                 sp_style_read_from_repr (style, repr); 
2805             }
2806             else
2807             {
2808                 multiple = true;
2809             }
2810         }
2811     }
2812     
2813     if (!style) return;
2814     if (multiple)
2815     {
2816         g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2817         gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), -1); 
2818         g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2819         return;
2820     }
2822     Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (style->text->font_family.value);
2824     g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2826     gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), gtk_tree_path_get_indices (path.gobj())[0]);
2828     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2829     SPCSSAttr *css = sp_repr_css_attr_new (); 
2830     items = sp_desktop_selection(desktop)->itemList();
2832     sp_repr_css_set_property (css, "font-family", gtk_combo_box_get_active_text (GTK_COMBO_BOX(cbox)));
2833     sp_desktop_set_style (desktop, css, true);
2835     for (; items != NULL; items = items->next)
2836     {
2837         // apply style to the reprs of all text objects in the selection
2838         if (SP_IS_TEXT (items->data))
2839         {
2840             // backwards compatibility:
2841             SP_OBJECT_REPR(items->data)->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL));
2842         }
2843     }
2845     // complete the transaction
2846     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2847     sp_repr_css_attr_unref (css);
2849     g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2852 static void
2853 sp_text_toolbox_family_changed (GtkComboBox *cbox,
2854                                 GtkWidget   *tbl) 
2856     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2857     unsigned items = 0;
2858     const GSList *item_list = sp_desktop_selection(desktop)->itemList();
2859     SPCSSAttr *css = sp_repr_css_attr_new (); 
2861     if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
2863     sp_repr_css_set_property (css, "font-family", gtk_combo_box_get_active_text (cbox));
2864     sp_desktop_set_style(desktop, css, true);
2866     for (; item_list != NULL; item_list = item_list->next) {
2867         // apply style to the reprs of all text objects in the selection
2868         if (SP_IS_TEXT (item_list->data)) {
2870             // backwards compatibility:
2871             SP_OBJECT_REPR(item_list->data)->setAttribute("sodipodi:linespacing",
2872 sp_repr_css_property (css, "line-height", NULL));
2874             ++items;
2875         }
2876         else if (SP_IS_FLOWTEXT (item_list->data))
2877             // no need to set sodipodi:linespacing, because Inkscape never supported it on flowtext
2878             ++items;
2879     }
2881     // complete the transaction
2882     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2883     sp_repr_css_attr_unref (css);
2886 static GtkWidget*
2887 sp_text_toolbox_new (SPDesktop *desktop)
2889     GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
2891 #if 0
2892     GtkWidget   *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
2893     GtkTooltips *tt = gtk_tooltips_new();
2894     GtkWidget   *group;
2895 #endif
2897     //Font Family
2898     {
2899             GtkWidget *cbox = gtk_combo_box_entry_new_text ();
2900             Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
2901             gtk_combo_box_set_model (GTK_COMBO_BOX (cbox), GTK_TREE_MODEL (Glib::unwrap(store)));
2902             gtk_widget_set_size_request (cbox, 250, -1);
2903             aux_toolbox_space (tbl, 1);
2904             gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2905             g_object_set_data (G_OBJECT (tbl), "combo-box-family", cbox);
2906             g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
2907     }
2909     //Font Style
2910     {
2911             GtkWidget *cbox = gtk_combo_box_new_text ();
2912             gtk_widget_set_size_request (cbox, 144, -1);
2913             aux_toolbox_space (tbl, 1);
2914             gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2915             g_object_set_data (G_OBJECT (tbl), "combo-box-style", cbox);
2916     }
2918     sigc::connection *connection =
2919     new sigc::connection(sp_desktop_selection(desktop)->connectChanged (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
2920     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2922 #if 0
2923     //Font Size
2924     {
2925             GtkWidget *c = gtk_combo_new ();
2926             gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2927             gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2928             gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2929             gtk_widget_set_size_request (c, 64, -1);
2930             aux_toolbox_space(tbl, 1);
2931             gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2932     }
2934         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2935         //Bold
2936         {
2937             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2938             GtkWidget *button = gtk_toggle_button_new ();
2939             gtk_container_add (GTK_CONTAINER (button), px);
2940             gtk_widget_show(button);
2941             gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
2942             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2943             gtk_widget_set_sensitive(button, TRUE);
2944             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2945         }
2948         //Italic
2949         {
2950             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2951             GtkWidget *button = gtk_toggle_button_new ();
2952             gtk_container_add (GTK_CONTAINER (button), px);
2953             gtk_widget_show(button);
2954             gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
2955             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2956             gtk_widget_set_sensitive(button, TRUE);
2957             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2958         }
2960         //Underline
2961         {
2962             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2963             GtkWidget *button = gtk_toggle_button_new ();
2964             gtk_container_add (GTK_CONTAINER (button), px);
2965             gtk_widget_show(button);
2966             gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
2967             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2968             gtk_widget_set_sensitive(button, FALSE);
2969             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2970         }
2972         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2973         // align left
2974         {
2975             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2976             GtkWidget *b = group = gtk_radio_button_new (NULL);
2977                 gtk_container_add (GTK_CONTAINER (b), px);
2978             gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
2979             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2980             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2981             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2982         }
2984         // align center
2985         {
2986             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2987             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2988                 gtk_container_add (GTK_CONTAINER (b), px);
2989             // TRANSLATORS: `Center' here is a verb.
2990             gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
2991                 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2992             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2993             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2994         }
2996         // align right
2997         {
2998             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2999             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3000                 gtk_container_add (GTK_CONTAINER (b), px);
3001             gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
3002             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3003             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3004             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3005         }
3007         // full justification
3008         {
3009             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3010             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3011                 gtk_container_add (GTK_CONTAINER (b), px);
3012             gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
3013             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3014             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3015             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3016         }
3017         
3018                 
3019         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3020                 
3021         // horizontal
3022         {
3023         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3024         GtkWidget *b = group = gtk_radio_button_new (NULL);
3025                 gtk_container_add (GTK_CONTAINER (b), px);
3026         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3027         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3028         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3029         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3030         }
3032         // vertical
3033         {
3034         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3035         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3036                 gtk_container_add (GTK_CONTAINER (b), px);
3037         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3038         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3039         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3040         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3041         }
3043         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3045         // letter spacing
3046     {
3047         {
3048         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3049         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3050         gtk_container_add (GTK_CONTAINER (hb), image);
3051         gtk_widget_show(image);
3052         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3053         }
3054     
3055         {
3056             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3057                                              "tools.text", "letter_spacing", 0.0,
3058                                              us, tbl, FALSE, NULL,
3059                                              -1000.0, 1000.0, 0.1, 0.1,
3060                                              sp_text_letter_changed, 0.1, 1);
3061             gtk_widget_set_size_request (hb, 45, 6);
3062             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3063         }
3064     }
3066         // line spacing
3067     {
3068         {
3069         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3070         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3071         gtk_container_add (GTK_CONTAINER (hb), image);
3072         gtk_widget_show(image);
3073         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3074         }
3075     
3076         {
3077             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3078                                              "tools.text", "line_spacing", 0,
3079                                              us, tbl, FALSE, NULL,
3080                                              -1000.0, 1000.0, 0.1, 0.1,
3081                                              sp_text_line_changed, 0.1, 1);
3082             gtk_widget_set_size_request (hb, 45, 0);
3083             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3084         }
3085     }
3088     // horizontal kerning/vertical kerning units menu: create
3089     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3090     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3091     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3093     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3095     // horizontal kerning
3096     {
3097         {
3098         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3099         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3100         gtk_container_add (GTK_CONTAINER (hb), image);
3101         gtk_widget_show(image);
3102         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3103         }
3105         {
3106             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3107                                              "tools.text", "horizontal_kerning", 0,
3108                                              us, tbl, FALSE, NULL,
3109                                              -100.00, 100.00, 0.01, 0.1,
3110                                              sp_text_horiz_kern_changed);
3111             gtk_widget_set_size_request (hb, 45, 0);
3112             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3113         }
3114     }
3116     // vertical kerning
3117     {
3118         {
3119         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3120         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3121         gtk_container_add (GTK_CONTAINER (hb), image);
3122         gtk_widget_show(image);
3123         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3124         }
3125     
3126         {
3127             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3128                                              "tools.text", "vertical_kerning", 0,
3129                                              us, tbl, FALSE, NULL,
3130                                              -100.00, 100.00, 0.01, 0.1,
3131                                              sp_text_vert_kern_changed);
3132             gtk_widget_set_size_request (hb, 45, 0);
3133             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3134         }
3135     }
3137     // add the units menu
3138     gtk_widget_show(us);
3139     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3140     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3141     }
3143         // letter rotation
3144     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3145     {
3146         {
3147         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3148         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3149         gtk_container_add (GTK_CONTAINER (hb), image);
3150         gtk_widget_show(image);
3151         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3152         }
3153         {
3154             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3155                                              "tools.text", "letter_rotation", 0,
3156                                              us, tbl, FALSE, NULL,
3157                                              -180.0, 180.0, 0.1, 0.1,
3158                                              sp_text_letter_rotation_changed, 0.1, 1);
3159             gtk_widget_set_size_request (hb, 45, 0);
3160             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3161         }
3162         // rotation degree label
3163         {
3164         GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3165         gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3166         }
3167     }
3168         
3169         // Remove Manual Kerns
3170         {
3171         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3172         GtkWidget *button = gtk_button_new ();
3173         gtk_container_add (GTK_CONTAINER (button), px);
3174         gtk_widget_show(button);
3175         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3176         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3177         gtk_widget_set_sensitive(button, TRUE);
3178         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3179         }
3180 #endif
3182 #if 0
3183     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
3184     swatch->setWatchedTool ("tools.text", true);
3185     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
3186     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
3188     sp_set_font_size_smaller (tbl);
3189 #endif
3191     gtk_widget_show_all (tbl);
3192     return tbl;
3194 } // end of sp_text_toolbox_new()
3197 //#########################
3198 //##  Connector Toolbox  ##
3199 //#########################
3201 static void sp_connector_path_set_avoid(void)
3203     cc_selection_set_avoid(true);
3207 static void sp_connector_path_set_ignore(void)
3209     cc_selection_set_avoid(false);
3213 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3215     // quit if run by the _changed callbacks
3216     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3217         return;
3218     }
3219         
3220     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3221             "desktop");
3222     SPDocument *doc = sp_desktop_document(desktop);
3224     if (!sp_document_get_undo_sensitive(doc))
3225     {
3226         return;
3227     }
3229     // in turn, prevent callbacks from responding
3230     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3231     
3232     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3233     
3234     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3235     SP_OBJECT(desktop->namedview)->updateRepr();
3236     
3237     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3238     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3239         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3240         NR::Matrix m = NR::identity();
3241         avoid_item_move(&m, item);
3242     }
3244     if (items) {
3245         g_slist_free(items);
3246     }
3247     
3248     sp_document_done(doc);
3250     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3251     
3252     spinbutton_defocus(GTK_OBJECT(tbl));
3256 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3257         gchar const *name, gchar const *old_value, gchar const *new_value,
3258         bool is_interactive, gpointer data)
3260     GtkWidget *tbl = GTK_WIDGET(data);
3262     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3263         return;
3264     }
3265     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3266         return;
3267     }
3269     GtkAdjustment *adj = (GtkAdjustment*)
3270             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3271     gdouble spacing = defaultConnSpacing;
3272     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3273     
3274     gtk_adjustment_set_value(adj, spacing);
3278 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3279     NULL, /* child_added */
3280     NULL, /* child_removed */
3281     connector_tb_event_attr_changed,
3282     NULL, /* content_changed */
3283     NULL  /* order_changed */
3284 };
3287 static GtkWidget *
3288 sp_connector_toolbox_new(SPDesktop *desktop)
3290     GtkTooltips *tt = gtk_tooltips_new();
3291     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3292     
3293     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3294     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3296     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3297             AUX_BETWEEN_BUTTON_GROUPS);
3299     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3300             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3301             tt, _("Make connectors avoid selected objects"));
3303     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3304             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3305             tt, _("Make connectors ignore selected objects"));
3307     //  interval
3308     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3309             AUX_BETWEEN_BUTTON_GROUPS);
3311     // Spacing spinbox
3312     {
3313         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3314                 _("The amount of space left around objects by auto-routing connectors"),
3315                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3316                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3317                 connector_spacing_changed, 1, 0);
3319         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3320                 AUX_SPACING);
3321     }
3323     gtk_widget_show_all(tbl);
3324     sp_set_font_size_smaller (tbl);
3325     
3326     // Code to watch for changes to the connector-spacing attribute in
3327     // the XML.
3328     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3329     g_assert(repr != NULL);
3330         
3331     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3332             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3333     
3334     if (oldrepr) { // remove old listener
3335         sp_repr_remove_listener_by_data(oldrepr, tbl);
3336         Inkscape::GC::release(oldrepr);
3337         oldrepr = NULL;
3338         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3339     }
3341     if (repr) {
3342         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3343         Inkscape::GC::anchor(repr);
3344         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3345         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3346     }
3347     
3348     return tbl;
3350 } // end of sp_connector_toolbox_new()
3353 /*
3354   Local Variables:
3355   mode:c++
3356   c-file-style:"stroustrup"
3357   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3358   indent-tabs-mode:nil
3359   fill-column:99
3360   End:
3361 */
3362 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :