Code

init matrix variable, removes compiler warnings
[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"
72 #include "../connection-pool.h"
74 #include "mod360.h"
76 #include "toolbox.h"
78 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
79 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
81 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
82 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
83 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
84 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
85 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
86 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
87 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
88 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
89 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
90 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
91 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
92 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
94 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
97 static struct {
98     gchar const *type_name;
99     gchar const *data_name;
100     sp_verb_t verb;
101     sp_verb_t doubleclick_verb;
102 } const tools[] = {
103     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
104     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
105     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
106     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
107     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
108     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
109     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
110     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
111     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
112     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
113     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
114     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
115     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
116     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
117     { NULL, NULL, 0, 0 }
118 };
120 static struct {
121     gchar const *type_name;
122     gchar const *data_name;
123     GtkWidget *(*create_func)(SPDesktop *desktop);
124 } const aux_toolboxes[] = {
125     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
126     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
127     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
128     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
129     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
130     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
131     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
132     { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
133     { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
134     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
135     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
136     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
137     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
138     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
139     { NULL, NULL, NULL }
140 };
142 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
144 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
145 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
147 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
148 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
150 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
151 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
153 /* Global text entry widgets necessary for update */
154 /* GtkWidget *dropper_rgb_entry, 
155           *dropper_opacity_entry ; */
156 // should be made a private member once this is converted to class
158 static void delete_connection(GObject *obj, sigc::connection *connection) {
159     connection->disconnect();
160     delete connection;
163 static GtkWidget *
164 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
165                       GtkTooltips *tt, gchar const *tip)
167     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
168     gtk_widget_show(b);
169     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
170     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
172     return b;
175 GtkWidget *
176 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
177                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
178                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
180     SPAction *action = verb->get_action(view);
181     if (!action) return NULL;
183     SPAction *doubleclick_action;
184     if (doubleclick_verb)
185         doubleclick_action = doubleclick_verb->get_action(view);
186     else
187         doubleclick_action = NULL;
189     /* fixme: Handle sensitive/unsensitive */
190     /* fixme: Implement sp_button_new_from_action */
191     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
192     gtk_widget_show(b);
193     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
195     return b;
198 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
199                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
201     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
204 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
205                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
207     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
210 GtkWidget *
211 sp_tool_toolbox_new()
213     GtkTooltips *tt = gtk_tooltips_new();
214     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
216     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
217     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
219     gtk_widget_set_sensitive(tb, FALSE);
221     GtkWidget *hb = gtk_handle_box_new();
222     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
223     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
224     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
226     gtk_container_add(GTK_CONTAINER(hb), tb);
227     gtk_widget_show(GTK_WIDGET(tb));
229     sigc::connection* conn = new sigc::connection;
230     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
232     return hb;
235 static void
236 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
238     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
239     gtk_widget_queue_resize(child);
242 static void
243 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
245     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
246     gtk_widget_queue_resize(child);
249 GtkWidget *
250 sp_aux_toolbox_new()
252     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
254     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
255     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
256     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
257     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
258     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
260     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
261     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
263     gtk_widget_set_sensitive(tb, FALSE);
265     GtkWidget *hb = gtk_handle_box_new();
266     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
267     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
268     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
270     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
271     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
273     gtk_container_add(GTK_CONTAINER(hb), tb);
274     gtk_widget_show(GTK_WIDGET(tb));
276     sigc::connection* conn = new sigc::connection;
277     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
279     return hb;
282 //####################################
283 //# Commands Bar
284 //####################################
286 GtkWidget *
287 sp_commands_toolbox_new()
289     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
291     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
292     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
293     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
294     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
295     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
297     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
298     gtk_widget_set_sensitive(tb, FALSE);
300     GtkWidget *hb = gtk_handle_box_new();
301     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
302     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
303     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
305     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
306     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
308     gtk_container_add(GTK_CONTAINER(hb), tb);
309     gtk_widget_show(GTK_WIDGET(tb));
311     sigc::connection* conn = new sigc::connection;
312     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
314     return hb;
318 //####################################
319 //# node editing callbacks
320 //####################################
322 void
323 sp_node_path_edit_add(void)
325     sp_node_selected_add_node();
328 void
329 sp_node_path_edit_delete(void)
331     sp_node_selected_delete();
334 void
335 sp_node_path_edit_delete_segment(void)
337     sp_node_selected_delete_segment();
340 void
341 sp_node_path_edit_break(void)
343     sp_node_selected_break();
346 void
347 sp_node_path_edit_join(void)
349     sp_node_selected_join();
352 void
353 sp_node_path_edit_join_segment(void)
355     sp_node_selected_join_segment();
358 void
359 sp_node_path_edit_toline(void)
361     sp_node_selected_set_line_type(NR_LINETO);
364 void
365 sp_node_path_edit_tocurve(void)
367     sp_node_selected_set_line_type(NR_CURVETO);
370 void
371 sp_node_path_edit_cusp(void)
373     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
376 void
377 sp_node_path_edit_smooth(void)
379     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
382 void
383 sp_node_path_edit_symmetrical(void)
385     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
388 static void toggle_show_handles (GtkWidget *button, gpointer data) {
389     bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
390     prefs_set_int_attribute ("tools.nodes", "show_handles",  show ? 1 : 0);
391     sp_nodepath_show_handles(show);
394 //################################
395 //##    Node Editing Toolbox    ##
396 //################################
398 static GtkWidget *
399 sp_node_toolbox_new(SPDesktop *desktop)
401     Inkscape::UI::View::View *view = desktop;
403     GtkTooltips *tt = gtk_tooltips_new();
404     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
406     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
408     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
409         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
410     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
411         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
413     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
415     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
416         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
417     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
418         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
420     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
421         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
423     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
424         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
426     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
428     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
429         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
431     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
432         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
434     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
435         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
437     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
439     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
440         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
442     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
443         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
445     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
447     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
449     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
451     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
453     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
454     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
456     {
457     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
458                                               SP_BUTTON_TYPE_TOGGLE,
459                                               NULL,
460                                               "nodes_show_handles",
461                                               _("Show the Bezier handles of selected nodes"),
462                                               tt);
463     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
464     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
465     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
466     }
468     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
469     gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
471     gtk_widget_show_all(tb);
473     return tb;
475 } // end of sp_node_toolbox_new()
478 //########################
479 //##    Zoom Toolbox    ##
480 //########################
482 static GtkWidget *
483 sp_zoom_toolbox_new(SPDesktop *desktop)
485     Inkscape::UI::View::View *view=desktop;
487     GtkTooltips *tt = gtk_tooltips_new();
488     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
490     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
491                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
493     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);
495     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);
497     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
499     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);
501     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);
503     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);
505     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);
507     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
509     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);
511     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);
513     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
515     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);
517     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);
519     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);
521     gtk_widget_show_all(tb);
523     return tb;
525 } // end of sp_zoom_toolbox_new()
527 void
528 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
530     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")));
534 void
535 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
537     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")));
540 void
541 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
543     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")));
546 static void
547 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
549     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
550     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
552     if (old_desktop) {
553         GList *children, *iter;
555         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
556         for ( iter = children ; iter ; iter = iter->next ) {
557             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
558         }
559         g_list_free(children);
560     }
562     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
564     if (desktop) {
565         gtk_widget_set_sensitive(toolbox, TRUE);
566         setup_func(toolbox, desktop);
567         update_func(desktop, desktop->event_context, toolbox);
568         *conn = desktop->connectEventContextChanged 
569             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
570     } else {
571         gtk_widget_set_sensitive(toolbox, FALSE);
572     }
574 } // end of toolbox_set_desktop()
577 static void
578 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
580     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
581     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
582     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
584     for (int i = 0 ; tools[i].type_name ; i++ ) {
585         GtkWidget *button =
586             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
587                                                               SP_BUTTON_TYPE_TOGGLE,
588                                                               Inkscape::Verb::get(tools[i].verb),
589                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
590                                                               desktop,
591                                                               tooltips );
593         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
594                            (gpointer)button );
595     }
599 static void
600 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
602     gchar const *const tname = ( eventcontext
603                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
604                                  : NULL );
605     for (int i = 0 ; tools[i].type_name ; i++ ) {
606         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
607         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
608     }
611 static void
612 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
614     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
616     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
617         GtkWidget *sub_toolbox;
618         if (aux_toolboxes[i].create_func == NULL)
619             sub_toolbox = sp_empty_toolbox_new(desktop);
620         else
621             sub_toolbox = aux_toolboxes[i].create_func(desktop);
623         gtk_size_group_add_widget( grouper, sub_toolbox );
625         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
626         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
627     }
628     g_object_unref( G_OBJECT(grouper) );
631 static void
632 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
634     gchar const *tname = ( eventcontext
635                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
636                            : NULL );
637     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
638         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
639         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
640             gtk_widget_show_all(sub_toolbox);
641             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
642         } else {
643             gtk_widget_hide(sub_toolbox);
644         }
645     }
648 static void
649 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
651     Inkscape::UI::View::View *view = desktop;
653     GtkTooltips *tt = gtk_tooltips_new();
654     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
656     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
657     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
659     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
660     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
661     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
662     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
664     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
666     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
667     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
669     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
671     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
672     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
674     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
676     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
677     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
678     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
680     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
682     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
683     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
684     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
686     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
688     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
689     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
690     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
692     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
694     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
695     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
697     // disabled until we have icons for them:
699     //find
701     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
702     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
704     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
706     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
707     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
708     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
709     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
711     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
713     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
714     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
716     gtk_widget_show_all(tb);
718     gtk_container_add(GTK_CONTAINER(toolbox), tb);
721 static void
722 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
726 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
728     gtk_widget_show(toolbox_toplevel);
729     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
731     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
732     if (!shown_toolbox) {
733         return;
734     }
735     gtk_widget_show(toolbox);
737     // need to show the spacer, or the padding will be off
738     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
739     gtk_widget_show(spacer);
741     gtk_widget_show_all(shown_toolbox);
744 void
745 aux_toolbox_space(GtkWidget *tb, gint space)
747     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
750 static GtkWidget *
751 sp_empty_toolbox_new(SPDesktop *desktop)
753     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
754     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
755     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
757     gtk_widget_show_all(tbl);
758     sp_set_font_size_smaller (tbl);
760     return tbl;
763 // helper UI functions
765 GtkWidget *
766 sp_tb_spinbutton(
767     gchar *label, gchar const *tooltip,
768     gchar const *path, gchar const *data, gdouble def,
769     GtkWidget *us,
770     GtkWidget *tbl,
771     gboolean altx, gchar const *altx_mark,
772     gdouble lower, gdouble upper, gdouble step, gdouble page,
773     void (*callback)(GtkAdjustment *, GtkWidget *),
774     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
776     GtkTooltips *tt = gtk_tooltips_new();
778     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
780     GtkWidget *l = gtk_label_new(label);
781     gtk_widget_show(l);
782     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
783     gtk_container_add(GTK_CONTAINER(hb), l);
785     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
786                                       lower, upper, step, page, page);
787     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
788     if (us)
789         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
791     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
792     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
793     if (altx)
794         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
795     gtk_widget_set_size_request(sb, 
796                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
797                                 AUX_SPINBUTTON_HEIGHT);
798     gtk_widget_show(sb);
799     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
800     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
801     gtk_container_add(GTK_CONTAINER(hb), sb);
802     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
804     return hb;
807 #define MODE_LABEL_WIDTH 70
809 //########################
810 //##       Star         ##
811 //########################
813 static void
814 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
816     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
818     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
819         // do not remember prefs if this call is initiated by an undo change, because undoing object
820         // creation sets bogus values to its attributes before it is deleted
821         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
822     }
824     // quit if run by the attr_changed listener
825     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
826         return;
827     }
829     // in turn, prevent listener from responding
830     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
832     bool modmade = false;
834     Inkscape::Selection *selection = sp_desktop_selection(desktop);
835     GSList const *items = selection->itemList();
836     for (; items != NULL; items = items->next) {
837         if (SP_IS_STAR((SPItem *) items->data)) {
838             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
839             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
840             sp_repr_set_svg_double(repr, "sodipodi:arg2",
841                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
842                                     + M_PI / (gint)adj->value));
843             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
844             modmade = true;
845         }
846     }
847     if (modmade)  sp_document_done(sp_desktop_document(desktop));
849     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
851     spinbutton_defocus(GTK_OBJECT(tbl));
854 static void
855 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
857     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
859     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
860         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
861     }
863     // quit if run by the attr_changed listener
864     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
865         return;
866     }
868     // in turn, prevent listener from responding
869     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
871     bool modmade = false;
872     Inkscape::Selection *selection = sp_desktop_selection(desktop);
873     GSList const *items = selection->itemList();
874     for (; items != NULL; items = items->next) {
875         if (SP_IS_STAR((SPItem *) items->data)) {
876             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
878             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
879             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
880             if (r2 < r1) {
881                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
882             } else {
883                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
884             }
886             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
887             modmade = true;
888         }
889     }
891     if (modmade) sp_document_done(sp_desktop_document(desktop));
893     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
895     spinbutton_defocus(GTK_OBJECT(tbl));
898 static void
899 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
901     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
903     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
904         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
905             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
906         } else {
907             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
908         }
909     }
911     // quit if run by the attr_changed listener
912     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
913         return;
914     }
916     // in turn, prevent listener from responding
917     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
919     Inkscape::Selection *selection = sp_desktop_selection(desktop);
920     GSList const *items = selection->itemList();
921     GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
922     bool modmade = false;
923     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
924         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
925         for (; items != NULL; items = items->next) {
926             if (SP_IS_STAR((SPItem *) items->data)) {
927                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
928                 repr->setAttribute("inkscape:flatsided", "true");
929                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
930                 modmade = true;
931             }
932         }
933     } else {
934         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
935         for (; items != NULL; items = items->next) {
936             if (SP_IS_STAR((SPItem *) items->data)) {
937                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
938                 repr->setAttribute("inkscape:flatsided", "false");
939                 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
940                 modmade = true;
941             }
942         }
943     }
944     if (modmade) sp_document_done(sp_desktop_document(desktop));
946     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
948     spinbutton_defocus(GTK_OBJECT(tbl));
951 static void
952 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
954     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
956     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
957         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
958     }
960     // quit if run by the attr_changed listener
961     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
962         return;
963     }
965     // in turn, prevent listener from responding
966     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
968     bool modmade = false;
970     Inkscape::Selection *selection = sp_desktop_selection(desktop);
971     GSList const *items = selection->itemList();
972     for (; items != NULL; items = items->next) {
973         if (SP_IS_STAR((SPItem *) items->data)) {
974             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
975             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
976             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
977             modmade = true;
978         }
979     }
980     if (modmade)  sp_document_done(sp_desktop_document(desktop));
982     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
984     spinbutton_defocus(GTK_OBJECT(tbl));
988 static void
989 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
991     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
993     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
994         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
995     }
997     // quit if run by the attr_changed listener
998     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
999         return;
1000     }
1002     // in turn, prevent listener from responding
1003     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1005     bool modmade = false;
1007     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1008     GSList const *items = selection->itemList();
1009     for (; items != NULL; items = items->next) {
1010         if (SP_IS_STAR((SPItem *) items->data)) {
1011             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1012             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1013             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1014             modmade = true;
1015         }
1016     }
1017     if (modmade)  sp_document_done(sp_desktop_document(desktop));
1019     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1021     spinbutton_defocus(GTK_OBJECT(tbl));
1025 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1026                                        gchar const *old_value, gchar const *new_value,
1027                                        bool is_interactive, gpointer data)
1029     GtkWidget *tbl = GTK_WIDGET(data);
1031     // quit if run by the _changed callbacks
1032     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1033         return;
1034     }
1036     // in turn, prevent callbacks from responding
1037     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1039     GtkAdjustment *adj;
1041     if (!strcmp(name, "inkscape:randomized")) {
1042         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1043         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1044     } else if (!strcmp(name, "inkscape:rounded")) {
1045         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1046         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1047     } else if (!strcmp(name, "inkscape:flatsided")) {
1048         GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1049         GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1050         char const *flatsides = repr->attribute("inkscape:flatsided");
1051         if (flatsides && !strcmp(flatsides,"false" )) {
1052             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1053             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1054         } else {
1055             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1056             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1057         }
1058     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1059         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1060         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1061         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1062         if (r2 < r1) {
1063             gtk_adjustment_set_value(adj, r2/r1);
1064         } else {
1065             gtk_adjustment_set_value(adj, r1/r2);
1066         }
1067     } else if (!strcmp(name, "sodipodi:sides")) {
1068         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1069         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1070     }
1072     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1076 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1078     NULL, /* child_added */
1079     NULL, /* child_removed */
1080     star_tb_event_attr_changed,
1081     NULL, /* content_changed */
1082     NULL  /* order_changed */
1083 };
1086 /**
1087  *  \param selection Should not be NULL.
1088  */
1089 static void
1090 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1092     int n_selected = 0;
1093     Inkscape::XML::Node *repr = NULL;
1094     Inkscape::XML::Node *oldrepr = NULL;
1096     for (GSList const *items = selection->itemList();
1097          items != NULL;
1098          items = items->next)
1099     {
1100         if (SP_IS_STAR((SPItem *) items->data)) {
1101             n_selected++;
1102             repr = SP_OBJECT_REPR((SPItem *) items->data);
1103         }
1104     }
1106     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1108     if (n_selected == 0) {
1109         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1110     } else if (n_selected == 1) {
1111         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1113         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1114         if (oldrepr) { // remove old listener
1115             sp_repr_remove_listener_by_data(oldrepr, tbl);
1116             Inkscape::GC::release(oldrepr);
1117             oldrepr = 0;
1118             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1119         }
1121         if (repr) {
1122             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1123             Inkscape::GC::anchor(repr);
1124             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1125             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1126         }
1127     } else {
1128         // FIXME: implement averaging of all parameters for multiple selected stars
1129         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1130         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1131     }
1135 static void
1136 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1138     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1139     // callbacks to lump all the changes for all selected objects in one undo step
1141     GtkAdjustment *adj;
1143     // fixme: make settable in prefs!
1144     gint mag = 5;
1145     gdouble prop = 0.5;
1146     gboolean flat = FALSE;
1147     gdouble randomized = 0;
1148     gdouble rounded = 0;
1150     GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1151     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  flat);
1152     GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1153     gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1155     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1156     gtk_adjustment_set_value(adj, mag);
1157     gtk_adjustment_value_changed(adj);
1159     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1160     gtk_adjustment_set_value(adj, prop);
1161     gtk_adjustment_value_changed(adj);
1163     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1164     gtk_adjustment_set_value(adj, rounded);
1165     gtk_adjustment_value_changed(adj);
1167     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1168     gtk_adjustment_set_value(adj, randomized);
1169     gtk_adjustment_value_changed(adj);
1171     spinbutton_defocus(GTK_OBJECT(tbl));
1175 void
1176 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1178     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1179     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1180     GtkWidget *l = gtk_label_new(NULL);
1181     gtk_label_set_markup(GTK_LABEL(l), title);
1182     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1183     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1184     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1188 static GtkWidget *
1189 sp_star_toolbox_new(SPDesktop *desktop)
1191     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1193     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1194     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1196     GtkTooltips *tt = gtk_tooltips_new();
1198     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1200     gchar const *flatsidedstr = NULL;
1202     /* Flatsided checkbox */
1203     {
1204         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1205         GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1206         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1207         flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1208         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1209             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1210         else
1211             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1212         gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1213         gtk_widget_show(fscb);
1214         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1215         gtk_container_add(GTK_CONTAINER(hb), fscb);
1216         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1217         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1218     }
1220     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1222     /* Magnitude */
1223     {
1224         GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1225                                          "tools.shapes.star", "magnitude", 3,
1226                                          NULL, tbl, TRUE, "altx-star",
1227                                          3, 1024, 1, 1,
1228                                          sp_stb_magnitude_value_changed, 1, 0);
1229         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1230     }
1232     /* Spoke ratio */
1233     {
1234         GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1235                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1236                                          // Base radius is the same for the closest handle.
1237                                          _("Base radius to tip radius ratio"),
1238                                          "tools.shapes.star", "proportion", 0.5,
1239                                          NULL, tbl, FALSE, NULL,
1240                                          0.01, 1.0, 0.01, 0.1,
1241                                          sp_stb_proportion_value_changed);
1242         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1243         g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1244         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1245             gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1246         else
1247             gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1248     }
1250     /* Roundedness */
1251     {
1252         GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1253                                          "tools.shapes.star", "rounded", 0.0,
1254                                          NULL, tbl, FALSE, NULL,
1255                                          -100.0, 100.0, 0.01, 0.1,
1256                                          sp_stb_rounded_value_changed);
1257         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1258     }
1260     /* Randomization */
1261     {
1262         GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1263                                          "tools.shapes.star", "randomized", 0.0,
1264                                          NULL, tbl, FALSE, NULL,
1265                                          -10.0, 10.0, 0.001, 0.01,
1266                                          sp_stb_randomized_value_changed, 0.1, 3);
1267         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1268     }
1270     aux_toolbox_space(tbl, AUX_SPACING);
1272     /* Reset */
1273     {
1274         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1275         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1276         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1277         gtk_widget_show(b);
1278         gtk_container_add(GTK_CONTAINER(hb), b);
1279         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1280         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1281     }
1283     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1284     swatch->setWatchedTool ("tools.shapes.star", true);
1285     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1286     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1288     gtk_widget_show_all(tbl);
1289     sp_set_font_size_smaller (tbl);
1291     sigc::connection *connection = new sigc::connection(
1292         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1293         );
1294     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1296     return tbl;
1300 //########################
1301 //##       Rect         ##
1302 //########################
1304 static void 
1305 sp_rtb_sensitivize (GtkWidget *tbl)
1307     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1308     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1309     GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1311     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1312         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1313     } else {
1314         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1315     }
1319 static void
1320 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1321                           void (*setter)(SPRect *, gdouble))
1323     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1325     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1326     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1328     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1329         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1330     }
1332     // quit if run by the attr_changed listener
1333     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1334         return;
1335     }
1337     // in turn, prevent listener from responding
1338     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1340     bool modmade = false;
1341     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1342     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1343         if (SP_IS_RECT(items->data)) {
1344             if (adj->value != 0) {
1345                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1346             } else {
1347                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1348             }
1349             modmade = true;
1350         }
1351     }
1353     sp_rtb_sensitivize (tbl);
1355     if (modmade) {
1356         sp_document_done(sp_desktop_document(desktop));
1357     }
1359     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1361     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1362     spinbutton_defocus(GTK_OBJECT(tbl));
1365 static void
1366 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1368     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1371 static void
1372 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1374     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1377 static void
1378 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1380     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1383 static void
1384 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1386     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1391 static void
1392 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1394     GtkWidget *tbl = GTK_WIDGET(obj);
1396     GtkAdjustment *adj;
1398     adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1399     gtk_adjustment_set_value(adj, 0.0);
1400     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1401     gtk_adjustment_value_changed(adj);
1403     adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1404     gtk_adjustment_set_value(adj, 0.0);
1405     gtk_adjustment_value_changed(adj);
1407     sp_rtb_sensitivize (tbl);
1409     spinbutton_defocus(GTK_OBJECT(tbl));
1412 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1413                                        gchar const *old_value, gchar const *new_value,
1414                                        bool is_interactive, gpointer data)
1416     GtkWidget *tbl = GTK_WIDGET(data);
1418     // quit if run by the _changed callbacks
1419     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1420         return;
1421     }
1423     // in turn, prevent callbacks from responding
1424     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1426     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1427     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1429     SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1430     if (SP_IS_RECT(item)) {
1431         {
1432             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1433             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1434             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1435         }
1437         {
1438             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1439             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1440             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1441         }
1443         {
1444             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1445             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1446             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1447         }
1449         {
1450             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1451             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1452             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1453         }
1454     }
1456     sp_rtb_sensitivize (tbl);
1458     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1462 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1463     NULL, /* child_added */
1464     NULL, /* child_removed */
1465     rect_tb_event_attr_changed,
1466     NULL, /* content_changed */
1467     NULL  /* order_changed */
1468 };
1470 /**
1471  *  \param selection should not be NULL.
1472  */
1473 static void
1474 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1476     int n_selected = 0;
1477     Inkscape::XML::Node *repr = NULL;
1478     SPItem *item = NULL;
1479     Inkscape::XML::Node *oldrepr = NULL;
1481     for (GSList const *items = selection->itemList();
1482          items != NULL;
1483          items = items->next) {
1484         if (SP_IS_RECT((SPItem *) items->data)) {
1485             n_selected++;
1486             item = (SPItem *) items->data;
1487             repr = SP_OBJECT_REPR(item);
1488         }
1489     }
1491     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1493     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1495     if (n_selected == 0) {
1496         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1498         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1499         gtk_widget_set_sensitive(w, FALSE);
1500         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1501         gtk_widget_set_sensitive(h, FALSE);
1503     } else if (n_selected == 1) {
1504         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1505         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1507         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1508         gtk_widget_set_sensitive(w, TRUE);
1509         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1510         gtk_widget_set_sensitive(h, TRUE);
1512         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1513         if (oldrepr) { // remove old listener
1514             sp_repr_remove_listener_by_data(oldrepr, tbl);
1515             Inkscape::GC::release(oldrepr);
1516             oldrepr = 0;
1517             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1518         }
1519         if (repr) {
1520             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1521             g_object_set_data(G_OBJECT(tbl), "item", item);
1522             Inkscape::GC::anchor(repr);
1523             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1524             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1525         }
1526     } else {
1527         // FIXME: implement averaging of all parameters for multiple selected
1528         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1529         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1530         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1531     }
1535 static GtkWidget *
1536 sp_rect_toolbox_new(SPDesktop *desktop)
1538     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1540     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1541     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1543     GtkTooltips *tt = gtk_tooltips_new();
1545     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1547     // rx/ry units menu: create
1548     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1549     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1550     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1551     // fixme: add % meaning per cent of the width/height
1553     /* W */
1554     {
1555         GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1556                                          "tools.shapes.rect", "width", 0,
1557                                          us, tbl, TRUE, "altx-rect",
1558                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1559                                          sp_rtb_width_value_changed);
1560         gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1561         gtk_widget_set_sensitive(hb, FALSE);
1562         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1563     }
1565     /* H */
1566     {
1567         GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1568                                          "tools.shapes.rect", "height", 0,
1569                                          us, tbl, FALSE, NULL,
1570                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1571                                          sp_rtb_height_value_changed);
1572         gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1573         gtk_widget_set_sensitive(hb, FALSE);
1574         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1575     }
1577     /* rx */
1578     {
1579         GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1580                                          "tools.shapes.rect", "rx", 0,
1581                                          us, tbl, FALSE, NULL,
1582                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1583                                          sp_rtb_rx_value_changed);
1584         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1585     }
1587     /* ry */
1588     {
1589         GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1590                                          "tools.shapes.rect", "ry", 0,
1591                                          us, tbl, FALSE, NULL,
1592                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1593                                          sp_rtb_ry_value_changed);
1594         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1595     }
1597     // add the units menu
1598     gtk_widget_show(us);
1599     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1600     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1602     /* Reset */
1603     {
1604         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1605         GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1606         gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1607         gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1608         gtk_widget_show(b);
1609         gtk_container_add(GTK_CONTAINER(hb), b);
1610         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1611         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1612     }
1614     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1615     swatch->setWatchedTool ("tools.shapes.rect", true);
1616     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1617     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1619     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1620     sp_rtb_sensitivize (tbl);
1622     gtk_widget_show_all(tbl);
1623     sp_set_font_size_smaller (tbl);
1625     sigc::connection *connection = new sigc::connection(
1626         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1627         );
1628     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1630     return tbl;
1633 //########################
1634 //##       Spiral       ##
1635 //########################
1637 static void
1638 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1640     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1642     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1643         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1644     }
1646     // quit if run by the attr_changed listener
1647     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1648         return;
1649     }
1651     // in turn, prevent listener from responding
1652     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1654     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1656     bool modmade = false;
1657     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1658          items != NULL;
1659          items = items->next)
1660     {
1661         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1662             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1663             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1664             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1665             modmade = true;
1666         }
1667     }
1669     g_free(namespaced_name);
1671     if (modmade) {
1672         sp_document_done(sp_desktop_document(desktop));
1673     }
1675     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1677     spinbutton_defocus(GTK_OBJECT(tbl));
1680 static void
1681 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1683     sp_spl_tb_value_changed(adj, tbl, "revolution");
1686 static void
1687 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1689     sp_spl_tb_value_changed(adj, tbl, "expansion");
1692 static void
1693 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1695     sp_spl_tb_value_changed(adj, tbl, "t0");
1698 static void
1699 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1701     GtkWidget *tbl = GTK_WIDGET(obj);
1703     GtkAdjustment *adj;
1705     // fixme: make settable
1706     gdouble rev = 5;
1707     gdouble exp = 1.0;
1708     gdouble t0 = 0.0;
1710     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1711     gtk_adjustment_set_value(adj, rev);
1712     gtk_adjustment_value_changed(adj);
1714     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1715     gtk_adjustment_set_value(adj, exp);
1716     gtk_adjustment_value_changed(adj);
1718     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1719     gtk_adjustment_set_value(adj, t0);
1720     gtk_adjustment_value_changed(adj);
1722     spinbutton_defocus(GTK_OBJECT(tbl));
1726 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1727                                          gchar const *old_value, gchar const *new_value,
1728                                          bool is_interactive, gpointer data)
1730     GtkWidget *tbl = GTK_WIDGET(data);
1732     // quit if run by the _changed callbacks
1733     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1734         return;
1735     }
1737     // in turn, prevent callbacks from responding
1738     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1740     GtkAdjustment *adj;
1741     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1742     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1744     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1745     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1747     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1748     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1750     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1754 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1755     NULL, /* child_added */
1756     NULL, /* child_removed */
1757     spiral_tb_event_attr_changed,
1758     NULL, /* content_changed */
1759     NULL  /* order_changed */
1760 };
1762 static void
1763 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1765     int n_selected = 0;
1766     Inkscape::XML::Node *repr = NULL;
1767     Inkscape::XML::Node *oldrepr = NULL;
1769     for (GSList const *items = selection->itemList();
1770          items != NULL;
1771          items = items->next)
1772     {
1773         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1774             n_selected++;
1775             repr = SP_OBJECT_REPR((SPItem *) items->data);
1776         }
1777     }
1779     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1781     if (n_selected == 0) {
1782         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1783     } else if (n_selected == 1) {
1784         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1786         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1787         if (oldrepr) { // remove old listener
1788             sp_repr_remove_listener_by_data(oldrepr, tbl);
1789             Inkscape::GC::release(oldrepr);
1790             oldrepr = 0;
1791             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1792         }
1794         if (repr) {
1795             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1796             Inkscape::GC::anchor(repr);
1797             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1798             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1799         }
1800     } else {
1801         // FIXME: implement averaging of all parameters for multiple selected
1802         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1803         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1804     }
1808 static GtkWidget *
1809 sp_spiral_toolbox_new(SPDesktop *desktop)
1811     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1812     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1813     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1815     GtkTooltips *tt = gtk_tooltips_new();
1817     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1819     /* Revolution */
1820     {
1821         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1822                                          "tools.shapes.spiral", "revolution", 3.0,
1823                                          NULL, tbl, TRUE, "altx-spiral",
1824                                          0.01, 1024.0, 0.1, 1.0,
1825                                          sp_spl_tb_revolution_value_changed, 1, 2);
1826         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1827     }
1829     /* Expansion */
1830     {
1831         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1832                                          "tools.shapes.spiral", "expansion", 1.0,
1833                                          NULL, tbl, FALSE, NULL,
1834                                          0.0, 1000.0, 0.01, 1.0,
1835                                          sp_spl_tb_expansion_value_changed);
1836         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1837     }
1839     /* T0 */
1840     {
1841         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1842                                          "tools.shapes.spiral", "t0", 0.0,
1843                                          NULL, tbl, FALSE, NULL,
1844                                          0.0, 0.999, 0.01, 1.0,
1845                                          sp_spl_tb_t0_value_changed);
1846         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1847     }
1849     aux_toolbox_space(tbl, AUX_SPACING);
1851     /* Reset */
1852     {
1853         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1854         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1855         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1856         gtk_widget_show(b);
1857         gtk_container_add(GTK_CONTAINER(hb), b);
1858         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1859         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1860     }
1862     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1863     swatch->setWatchedTool ("tools.shapes.spiral", true);
1864     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1865     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1867     gtk_widget_show_all(tbl);
1868     sp_set_font_size_smaller (tbl);
1870     sigc::connection *connection = new sigc::connection(
1871         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1872         );
1873     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1875     return tbl;
1878 //########################
1879 //##     Pen/Pencil    ##
1880 //########################
1883 static GtkWidget *
1884 sp_pen_toolbox_new(SPDesktop *desktop)
1886     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1887     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1888     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1890     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1891     swatch->setWatchedTool ("tools.freehand.pen", true);
1892     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1893     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1895     gtk_widget_show_all(tbl);
1896     sp_set_font_size_smaller (tbl);
1898     return tbl;
1901 static GtkWidget *
1902 sp_pencil_toolbox_new(SPDesktop *desktop)
1904     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1905     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1906     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1908     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1909     swatch->setWatchedTool ("tools.freehand.pencil", true);
1910     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1911     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1913     gtk_widget_show_all(tbl);
1914     sp_set_font_size_smaller (tbl);
1916     return tbl;
1920 //########################
1921 //##     Calligraphy    ##
1922 //########################
1924 static void
1925 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1927     prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1928     spinbutton_defocus(GTK_OBJECT(tbl));
1931 static void
1932 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1934     prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1935     spinbutton_defocus(GTK_OBJECT(tbl));
1938 static void
1939 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1941     prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1942     spinbutton_defocus(GTK_OBJECT(tbl));
1945 static void
1946 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1948     prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1949     spinbutton_defocus(GTK_OBJECT(tbl));
1952 static void
1953 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1955     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1956     spinbutton_defocus(GTK_OBJECT(tbl));
1959 static void
1960 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1962     prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1963     spinbutton_defocus(GTK_OBJECT(tbl));
1966 static void
1967 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1969     prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1970     spinbutton_defocus(GTK_OBJECT(tbl));
1973 static void
1974 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1976     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1979 static void
1980 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1982     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1984     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1987 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
1989     // FIXME: make defaults settable via Inkscape Options
1990     struct KeyValue {
1991         char const *key;
1992         double value;
1993     } const key_values[] = {
1994         {"mass", 0.02},
1995         {"drag", 1.0},
1996         {"angle", 30.0},
1997         {"width", 15},
1998         {"thinning", 0.1},
1999         {"tremor", 0.0},
2000         {"flatness", 0.9}
2001     };
2003     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2004         KeyValue const &kv = key_values[i];
2005         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2006         gtk_adjustment_set_value(&adj, kv.value);
2007     }
2009     spinbutton_defocus(GTK_OBJECT(tbl));
2012 static GtkWidget *
2013 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2015     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2016     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2017     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2019     GtkTooltips *tt = gtk_tooltips_new();
2020     GtkWidget *calligraphy_angle;
2022     //  interval
2023     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2025     /* Width */
2026     {
2027         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2028                                          "tools.calligraphic", "width", 15,
2029                                          NULL, tbl, TRUE, "altx-calligraphy",
2030                                          1, 100, 1.0, 10.0,
2031                                          sp_ddc_width_value_changed,  0.01, 0, 100);
2032         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2033     }
2035     /* Thinning */
2036     {
2037         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)"),
2038                                          "tools.calligraphic", "thinning", 0.1,
2039                                          NULL, tbl, FALSE, NULL,
2040                                          -1.0, 1.0, 0.01, 0.1,
2041                                          sp_ddc_velthin_value_changed, 0.01, 2);
2042         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2043     }
2045     //  interval
2046     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2048     /* Angle */
2049     {
2050         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2051                                              "tools.calligraphic", "angle", 30,
2052                                              NULL, tbl, TRUE, "calligraphy-angle",
2053                                              -90.0, 90.0, 1.0, 10.0,
2054                                              sp_ddc_angle_value_changed, 1, 0);
2055         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2056     }
2058     /* Fixation */
2059     {
2060         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2061                                          "tools.calligraphic", "flatness", 0.9,
2062                                          NULL, tbl, FALSE, NULL,
2063                                          0.0, 1.0, 0.01, 0.1,
2064                                          sp_ddc_flatness_value_changed, 0.01, 2);
2065         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2066     }
2068     //  interval
2069     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2071     /* Tremor */
2072     {
2073         GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2074                                          "tools.calligraphic", "tremor", 0.0,
2075                                          NULL, tbl, FALSE, NULL,
2076                                          0.0, 1.0, 0.01, 0.1,
2077                                          sp_ddc_tremor_value_changed, 0.01, 2);
2078         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2079     }
2080     /* Mass */
2081     {
2082         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2083                                          "tools.calligraphic", "mass", 0.02,
2084                                          NULL, tbl, FALSE, NULL,
2085                                          0.0, 1.0, 0.01, 0.1,
2086                                          sp_ddc_mass_value_changed, 0.01, 2);
2087         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2088     }
2090     /* Drag */
2091     {
2092         // TRANSLATORS: "drag" means "resistance" here
2093         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2094                                          "tools.calligraphic", "drag", 1,
2095                                          NULL, tbl, FALSE, NULL,
2096                                          0.0, 1.0, 0.01, 0.1,
2097                                          sp_ddc_drag_value_changed, 0.01, 2);
2098         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2099     }
2101     //  interval
2102     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2104     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2105     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2107     /* Use Pressure button */
2108     {
2109     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2110                                                  SP_BUTTON_TYPE_TOGGLE,
2111                                                  NULL,
2112                                                  "use_pressure",
2113                                                  _("Use the pressure of the input device to alter the width of the pen"),
2114                                                  tt);
2115     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2116     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2117     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2118     }
2120     /* Use Tilt button */
2121     {
2122     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2123                                                  SP_BUTTON_TYPE_TOGGLE,
2124                                                  NULL,
2125                                                  "use_tilt",
2126                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2127                                                  tt);
2128     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2129     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2130     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2131     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2132     }
2134     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2135     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2137     /* Reset */
2138     {
2139         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2140         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2141         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2142         gtk_widget_show(b);
2143         gtk_container_add(GTK_CONTAINER(hb), b);
2144         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2145         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2146     }
2149     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2150     swatch->setWatchedTool ("tools.calligraphic", true);
2151     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2152     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2154     gtk_widget_show_all(tbl);
2155     sp_set_font_size_smaller (tbl);
2157     return tbl;
2161 //########################
2162 //##    Circle / Arc    ##
2163 //########################
2165 static void 
2166 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2168     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2169     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2171     if (v1 == 0 && v2 == 0) {
2172         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2173             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2174             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2175         }
2176     } else {
2177         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2178         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2179     }
2182 static void
2183 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2185     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2187     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2188         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2189     }
2191     // quit if run by the attr_changed listener
2192     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2193         return;
2194     }
2196     // in turn, prevent listener from responding
2197     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2199     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2201     bool modmade = false;
2202     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2203          items != NULL;
2204          items = items->next)
2205     {
2206         SPItem *item = SP_ITEM(items->data);
2208         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2210             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2211             SPArc *arc = SP_ARC(item);
2213             if (!strcmp(value_name, "start"))
2214                 ge->start = (adj->value * M_PI)/ 180;
2215             else
2216                 ge->end = (adj->value * M_PI)/ 180;
2218             sp_genericellipse_normalize(ge);
2219             ((SPObject *)arc)->updateRepr();
2220             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2222             modmade = true;
2223         }
2224     }
2226     g_free(namespaced_name);
2228     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2230     sp_arctb_sensitivize (tbl, adj->value, other->value);
2232     if (modmade) {
2233         sp_document_maybe_done(sp_desktop_document(desktop), value_name);
2234     }
2236     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2237     spinbutton_defocus(GTK_OBJECT(tbl));
2239     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2243 static void
2244 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2246     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2249 static void
2250 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2252     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2255 static void
2256 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2258     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2260     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2261         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2262             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2263         } else {
2264             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2265         }
2266     }
2268     // quit if run by the attr_changed listener
2269     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2270         return;
2271     }
2273     // in turn, prevent listener from responding
2274     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2276     bool modmade = false;
2278     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2279         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2280              items != NULL;
2281              items = items->next)
2282         {
2283             if (SP_IS_ARC((SPItem *) items->data)) {
2284                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2285                 repr->setAttribute("sodipodi:open", "true");
2286                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2287                 modmade = true;
2288             }
2289         }
2290     } else {
2291         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2292              items != NULL;
2293              items = items->next)
2294         {
2295             if (SP_IS_ARC((SPItem *) items->data))    {
2296                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2297                 repr->setAttribute("sodipodi:open", NULL);
2298                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2299                 modmade = true;
2300             }
2301         }
2302     }
2304     if (modmade) {
2305         sp_document_done(sp_desktop_document(desktop));
2306     }
2308     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2310     spinbutton_defocus(GTK_OBJECT(tbl));
2313 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2315     GtkWidget *tbl = GTK_WIDGET(obj);
2317     GtkAdjustment *adj;
2318     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2319     gtk_adjustment_set_value(adj, 0.0);
2320     gtk_adjustment_value_changed(adj);
2322     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2323     gtk_adjustment_set_value(adj, 0.0);
2324     gtk_adjustment_value_changed(adj);
2326     spinbutton_defocus(GTK_OBJECT(tbl));
2329 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2330                                       gchar const *old_value, gchar const *new_value,
2331                                       bool is_interactive, gpointer data)
2333     GtkWidget *tbl = GTK_WIDGET(data);
2335     // quit if run by the _changed callbacks
2336     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2337         return;
2338     }
2340     // in turn, prevent callbacks from responding
2341     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2343     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2344     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2346     GtkAdjustment *adj1,*adj2;
2347     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2348     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2349     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2350     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2352     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2354     char const *openstr = NULL;
2355     openstr = repr->attribute("sodipodi:open");
2356     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2358     if (openstr) {
2359         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2360     } else {
2361         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2362     }
2364     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2367 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2368     NULL, /* child_added */
2369     NULL, /* child_removed */
2370     arc_tb_event_attr_changed,
2371     NULL, /* content_changed */
2372     NULL  /* order_changed */
2373 };
2376 static void
2377 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2379     int n_selected = 0;
2380     Inkscape::XML::Node *repr = NULL;
2381     Inkscape::XML::Node *oldrepr = NULL;
2383     for (GSList const *items = selection->itemList();
2384          items != NULL;
2385          items = items->next)
2386     {
2387         if (SP_IS_ARC((SPItem *) items->data)) {
2388             n_selected++;
2389             repr = SP_OBJECT_REPR((SPItem *) items->data);
2390         }
2391     }
2393     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2395     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2396     if (n_selected == 0) {
2397         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2398     } else if (n_selected == 1) {
2399         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2400         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2402         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2404         if (oldrepr) { // remove old listener
2405             sp_repr_remove_listener_by_data(oldrepr, tbl);
2406             Inkscape::GC::release(oldrepr);
2407             oldrepr = 0;
2408             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2409         }
2411         if (repr) {
2412             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2413             Inkscape::GC::anchor(repr);
2414             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2415             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2416         }
2417     } else {
2418         // FIXME: implement averaging of all parameters for multiple selected
2419         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2420         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2421         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2422     }
2426 static GtkWidget *
2427 sp_arc_toolbox_new(SPDesktop *desktop)
2429     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2431     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2432     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2434     GtkTooltips *tt = gtk_tooltips_new();
2436     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2438     /* Start */
2439     {
2440         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2441                                          "tools.shapes.arc", "start", 0.0,
2442                                          NULL, tbl, TRUE, "altx-arc",
2443                                          -360.0, 360.0, 1.0, 10.0,
2444                                          sp_arctb_start_value_changed);
2445         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2446     }
2448     /* End */
2449     {
2450         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2451                                          "tools.shapes.arc", "end", 0.0,
2452                                          NULL, tbl, FALSE, NULL,
2453                                          -360.0, 360.0, 1.0, 10.0,
2454                                          sp_arctb_end_value_changed);
2455         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2456     }
2458     /* Segments / Pie checkbox */
2459     {
2460         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2461         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2462         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2464         gchar const *openstr = NULL;
2465         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2466         if (!openstr || (openstr && !strcmp(openstr, "false")))
2467             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2468         else
2469             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2471         gtk_widget_show(fscb);
2472         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2473         gtk_container_add(GTK_CONTAINER(hb), fscb);
2474         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2475         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2476     }
2478     /* Make Whole */
2479     {
2480         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2481         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2482         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2483         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2484         gtk_widget_show(b);
2485         gtk_container_add(GTK_CONTAINER(hb), b);
2486         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2487         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2488     }
2490     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2491     // sensitivize make whole and open checkbox
2492     {
2493         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2494         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2495         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2496     }
2498     sigc::connection *connection = new sigc::connection(
2499         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2500         );
2501     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2503     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2504     swatch->setWatchedTool ("tools.shapes.arc", true);
2505     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2506     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2508     gtk_widget_show_all(tbl);
2509     sp_set_font_size_smaller (tbl);
2511     return tbl;
2517 // toggle button callbacks and updaters
2519 //########################
2520 //##      Dropper       ##
2521 //########################
2523 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2524     prefs_set_int_attribute ("tools.dropper", "pick", 
2525         // 0 and 1 are backwards here because of pref
2526         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2530 /**
2531  * Copy the current saved desktop color to the clipboard as full hex + alpha
2532  * color representation. This is useful for passing values between various 
2533  * input boxes, or directly to xml.
2534  */
2535 /* static void
2536 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2538     GtkWidget *tbl = GTK_WIDGET(obj);
2539     
2540     SPDesktop *desktop = 
2541         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2543    
2544     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2545 }*/
2548 /**
2549  * Copies currently saved desktop color to the clipboard as a hex value. This 
2550  * is useful for editing webpages and needing a value quickly for web
2551  * colors.
2552  * 
2553  * TODO: When the toggle of the dropper is set to not mix color against 
2554  *       page background, this still just gets the color of the page and 
2555  *       doesn't get the actual mixed against background which is needed 
2556  *       for the hex value ppl. want for web pages, etc.
2557  */
2559 /* static void
2560 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2562     GtkWidget *tbl = GTK_WIDGET(obj);
2563     
2564     SPDesktop *desktop = 
2565         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2566     
2567     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2568 }*/
2571 /**
2572  * Sets the input boxes with the changed color and opacity. This is used as a 
2573  * callback for style changing.
2574  */
2575 /* static bool
2576 sp_style_changed (const SPCSSAttr *css, gpointer data)
2578     // GrDrag *drag = (GrDrag *) data;
2579     
2580     // set fill of text entry box
2581     if (css->attribute("fill"))
2582         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2583             css->attribute("fill")); 
2585     // set opacity of text entry box
2586     if (css->attribute("fill-opacity"))
2587         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2588             css->attribute("fill-opacity")); 
2589     
2590     // set fill of text entry box
2591     if (css->attribute("stroke"))
2592         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2593             css->attribute("stroke")); 
2595     // set opacity of text entry box
2596     if (css->attribute("stroke-opacity"))
2597         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2598             css->attribute("stroke-opacity"));
2599     return false;
2602 */
2605 /**
2606  * Dropper auxiliary toolbar construction and setup.
2607  *
2608  * TODO: Would like to add swatch of current color.
2609  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2610  *       can drag and drop places. Will provide a nice mixing palette.
2611  */
2612 static GtkWidget *
2613 sp_dropper_toolbox_new(SPDesktop *desktop)
2615     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2617     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2618     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2620     GtkTooltips *tt = gtk_tooltips_new();
2622     
2623     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2624                        AUX_BETWEEN_BUTTON_GROUPS);
2625     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2628     
2629     /* RGB Input Field */
2630  /*   {
2631         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2632         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2633         gtk_widget_show (dropper_rgba_label);
2634         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2635         
2636         dropper_rgb_entry = gtk_entry_new ();
2637         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2638         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2639         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2640         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2641                          _("Hexidecimal representation of last selected "
2642                            "color"), 
2643                          NULL);
2644         gtk_widget_show (dropper_rgb_entry);
2645         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2646         
2647         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2648                            AUX_BETWEEN_BUTTON_GROUPS);
2649     } */
2650     
2651     /* Opacity Input Field */
2652 /*    {
2653         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2654         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2655         gtk_widget_show (dropper_opacity_label);
2656         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2657         
2658         dropper_opacity_entry = gtk_entry_new ();
2659         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2660         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2661         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2662         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2663                          _("Opacity of last selected color"), 
2664                          NULL);
2665         gtk_widget_show (dropper_opacity_entry);
2666         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2667         
2668         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2669                            AUX_BETWEEN_BUTTON_GROUPS);
2670     } */
2671     
2672     
2673     /* Copy to Clipboard */
2674 /*    {
2675         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2676         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2677         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2678                                       "RGB + Alpha (RGBA) to "
2679                                       "clipboard"), 
2680                              NULL);
2681         gtk_widget_show(b);
2682         gtk_container_add(GTK_CONTAINER(hb), b);
2683         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2684             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2685         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2686                            AUX_BETWEEN_BUTTON_GROUPS);
2687     } */
2690     /* Copy to Clipboard as HEX */
2691 /*    {
2692         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2693         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2694         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2695                                       "hexidecimal RGB without alpha " 
2696                                       "to clipboard"), NULL);
2697         gtk_widget_show(b);
2698         gtk_container_add(GTK_CONTAINER(hb), b);
2699         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2700             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2701         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2702                            AUX_BETWEEN_BUTTON_GROUPS);
2703     } */
2704     
2705     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2706     
2707     {
2708         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2709         
2710         GtkWidget *button = 
2711             sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2712                                      SP_BUTTON_TYPE_TOGGLE,
2713                                      NULL,
2714                                      "pick_color",
2715                                      _("When pressed, picks visible color "
2716                                        "without alpha and when not pressed, "
2717                                        "picks color including its "
2718                                        "alpha"),
2719                                      tt);
2721         gtk_widget_show(button);
2722         gtk_container_add (GTK_CONTAINER (hb), button);
2724         g_signal_connect_after (G_OBJECT (button), "clicked", 
2725                                 G_CALLBACK (toggle_dropper_color_pick), NULL);
2726         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2727                                       !prefs_get_int_attribute ("tools.dropper", 
2728                                                                "pick", 0));
2729         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2730                    AUX_BETWEEN_BUTTON_GROUPS);
2731     }
2732    
2733     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2734     
2736     // where new gtkmm stuff should go
2737     
2738     gtk_widget_show_all(tbl);
2739     sp_set_font_size_smaller (tbl);
2741     /*
2742     sigc::connection *connection = new sigc::connection(
2743         desktop->connectSetStyle(
2744             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2745                        desktop)) ); 
2746     
2747     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2748                      connection); */
2749     
2750     return tbl;
2754 //########################
2755 //##    Text Toolbox    ##
2756 //########################
2757 /*
2758 static void
2759 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2761     //Call back for letter sizing spinbutton
2764 static void
2765 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2767     //Call back for line height spinbutton
2770 static void
2771 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2773     //Call back for horizontal kerning spinbutton
2776 static void
2777 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2779     //Call back for vertical kerning spinbutton
2782 static void
2783 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2785     //Call back for letter rotation spinbutton
2786 }*/
2788 namespace {
2790     void
2791     sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2792     {
2793         GtkComboBox *cbox = 0;
2794     
2795         SPStyle *query =
2796             sp_style_new ();
2798         int result_family =
2799             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); 
2801         int result_style =
2802             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); 
2804         int result_numbers =
2805             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2807         // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2808         if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2809         {
2810             Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
2812             if (repr)
2813             {
2814                 sp_style_read_from_repr (query, repr);
2815             }
2816             else
2817             {
2818                 return;
2819             }
2820         }
2822         if (result_numbers == QUERY_STYLE_MULTIPLE_DIFFERENT)
2823         {
2824             static char* cboxes[] = { "combo-box-family", "combo-box-style" };
2825         
2826             for (unsigned n = 0 ; n < G_N_ELEMENTS(cboxes); ++n)
2827             {
2828                 cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), cboxes[n]));
2829                 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2830                 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), -1); 
2831                 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2832             }
2833             gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2834             return;
2835         }
2837         if (query->text)
2838         {
2839             if (query->text->font_family.value) 
2840             {
2841                 Gtk::TreePath path;
2842                 try {
2843                     path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2844                 } catch (...) {
2845                     return;
2846                 }
2848                 cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), "combo-box-family"));
2849                 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2850                 gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), gtk_tree_path_get_indices (path.gobj())[0]);
2851                 g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2852             }
2854             //Style
2855             cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), "combo-box-style"));
2856             g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(1));
2857             gtk_combo_box_set_active (GTK_COMBO_BOX (cbox), gint(query->font_style.value));
2858             g_object_set_data (G_OBJECT (cbox), "block", GINT_TO_POINTER(0));
2860             gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2861         }
2862     }
2864     void
2865     sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl) 
2866     {
2867         sp_text_toolbox_selection_changed (selection, tbl); 
2868     }
2870     void
2871     sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
2872     {
2873         sp_text_toolbox_selection_changed (NULL, tbl); 
2874     }
2876     void
2877     sp_text_toolbox_family_changed (GtkComboBox *cbox,
2878                                     GtkWidget   *tbl) 
2879     {
2880         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2882         if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
2884         if (gtk_combo_box_get_active (cbox) < 0) return;
2886         SPCSSAttr *css = sp_repr_css_attr_new (); 
2887         sp_repr_css_set_property (css, "font-family", gtk_combo_box_get_active_text (cbox));
2888         sp_desktop_set_style (desktop, css, true, true);
2889         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2890         sp_repr_css_attr_unref (css);
2892         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2893     }
2895     void
2896     sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
2897                                            GtkWidget    *tbl) 
2898     {
2899         const char* family = gtk_entry_get_text (entry);
2901         try {    
2902             Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
2903             GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT(tbl), "combo-box-family"));
2904             gtk_combo_box_set_active (cbox, gtk_tree_path_get_indices (path.gobj())[0]);
2905             gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2906         } catch (...) {
2907             //XXX: Accept it anyway and show the warning
2908             if (family && strlen (family)) gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2909         }
2910     }
2912     void
2913     sp_text_toolbox_style_changed (GtkComboBox *cbox,
2914                                    GtkWidget   *tbl) 
2915     {
2916         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
2918         if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
2919     
2920         static char* styles[] = { "normal", "italic" , "oblique" };
2922         SPCSSAttr *css = sp_repr_css_attr_new (); 
2923         sp_repr_css_set_property (css, "font-style", styles[gtk_combo_box_get_active (cbox)]);
2924         sp_desktop_set_style (desktop, css, true, true);
2925         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2926         sp_repr_css_attr_unref (css);
2927     }
2929 }//<unnamed> namespace
2931 #if 0
2932 static void  cell_data_func  (GtkCellLayout     *cell_layout,
2933                               GtkCellRenderer   *cell,
2934                               GtkTreeModel      *tree_model,
2935                               GtkTreeIter       *iter,
2936                               gpointer           data)
2938     char *text; 
2939     gtk_tree_model_get (tree_model, iter, 0, &text, -1); 
2940     g_object_set (G_OBJECT (cell), "family", text, NULL);
2942 #endif
2944 namespace
2946     GtkWidget*
2947     sp_text_toolbox_new (SPDesktop *desktop)
2948     {
2949         GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
2951 #if 0
2952     GtkWidget   *us = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "units"));
2953     GtkTooltips *tt = gtk_tooltips_new();
2954     GtkWidget   *group;
2955 #endif
2957         //Font Family
2958         GtkWidget *cbox = gtk_combo_box_entry_new_text ();
2959         Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
2960         gtk_cell_layout_clear (GTK_CELL_LAYOUT (cbox));
2961         GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
2962         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (cbox), cell, FALSE);
2963         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (cbox), cell, "text", 0, NULL);
2964         GtkEntryCompletion *completion = gtk_entry_completion_new ();
2965         gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
2966         gtk_entry_completion_set_text_column (completion, 0);
2967         gtk_entry_completion_set_minimum_key_length (completion, 3); //3 characters minimum sounds reasonable
2968         g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
2970 #if 0
2971         gtk_cell_layout_set_cell_data_func
2972             (GTK_CELL_LAYOUT (cbox),
2973              cell, 
2974              GtkCellLayoutDataFunc (cell_data_func),
2975              tbl, 
2976              NULL); 
2977 #endif
2979         gtk_combo_box_set_model (GTK_COMBO_BOX (cbox), GTK_TREE_MODEL (Glib::unwrap(store)));
2980         gtk_widget_set_size_request (cbox, 250, -1);
2981         aux_toolbox_space (tbl, 1);
2982         gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
2983         g_object_set_data (G_OBJECT (tbl), "combo-box-family", cbox);
2984         g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
2985         g_signal_connect (G_OBJECT (GTK_BIN(cbox)->child), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
2986         gtk_entry_set_completion (GTK_ENTRY(GTK_BIN(cbox)->child), completion);
2988         GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
2989         aux_toolbox_space (tbl, 1);
2990         GtkWidget *box = gtk_event_box_new ();
2991         gtk_container_add (GTK_CONTAINER (box), image);
2992         gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
2993         g_object_set_data (G_OBJECT (tbl), "warning-image", box);
2994         GtkTooltips *tooltips = gtk_tooltips_new ();
2995         gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
2996         gtk_widget_hide (GTK_WIDGET (box));
2998         //Font Style
2999         cbox = gtk_combo_box_new_text ();
3000         gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _("Normal"));
3001         gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _("Italic"));
3002         gtk_combo_box_append_text (GTK_COMBO_BOX (cbox), _("Oblique"));
3003         gtk_widget_set_size_request (cbox, 144, -1);
3004         aux_toolbox_space (tbl, 1);
3005         gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3006         g_object_set_data (G_OBJECT (tbl), "combo-box-style", cbox);
3007         g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_style_changed), tbl);
3009         Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3011         sigc::connection *c_selection_changed =
3012             new sigc::connection (sp_desktop_selection (desktop)->connectChanged 
3013                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3014         pool->add_connection ("selection-changed", c_selection_changed);
3016         sigc::connection *c_selection_modified =
3017             new sigc::connection (sp_desktop_selection (desktop)->connectModified 
3018                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3019         pool->add_connection ("selection-modified", c_selection_modified);
3021         sigc::connection *c_subselection_changed =
3022             new sigc::connection (desktop->connectToolSubselectionChanged
3023                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3024         pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3026         Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3028 #if 0
3029     //Font Size
3030     {
3031             GtkWidget *c = gtk_combo_new ();
3032             gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
3033             gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
3034             gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
3035             gtk_widget_set_size_request (c, 64, -1);
3036             aux_toolbox_space(tbl, 1);
3037             gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
3038     }
3040     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3041     //Bold
3042     {
3043             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3044             GtkWidget *button = gtk_toggle_button_new ();
3045             gtk_container_add (GTK_CONTAINER (button), px);
3046             gtk_widget_show(button);
3047             gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
3048             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3049             gtk_widget_set_sensitive(button, TRUE);
3050             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3051     }
3054         //Italic
3055         {
3056             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3057             GtkWidget *button = gtk_toggle_button_new ();
3058             gtk_container_add (GTK_CONTAINER (button), px);
3059             gtk_widget_show(button);
3060             gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
3061             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3062             gtk_widget_set_sensitive(button, TRUE);
3063             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3064         }
3066         //Underline
3067         {
3068             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3069             GtkWidget *button = gtk_toggle_button_new ();
3070             gtk_container_add (GTK_CONTAINER (button), px);
3071             gtk_widget_show(button);
3072             gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
3073             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3074             gtk_widget_set_sensitive(button, FALSE);
3075             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3076         }
3078         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3079         // align left
3080         {
3081             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3082             GtkWidget *b = group = gtk_radio_button_new (NULL);
3083                 gtk_container_add (GTK_CONTAINER (b), px);
3084             gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
3085             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3086             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3087             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3088         }
3090         // align center
3091         {
3092             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3093             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3094                 gtk_container_add (GTK_CONTAINER (b), px);
3095             // TRANSLATORS: `Center' here is a verb.
3096             gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
3097                 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3098             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3099             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3100         }
3102         // align right
3103         {
3104             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3105             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3106                 gtk_container_add (GTK_CONTAINER (b), px);
3107             gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
3108             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3109             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3110             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3111         }
3113         // full justification
3114         {
3115             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3116             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3117                 gtk_container_add (GTK_CONTAINER (b), px);
3118             gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
3119             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3120             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3121             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3122         }
3123         
3124                 
3125         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3126                 
3127         // horizontal
3128         {
3129         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3130         GtkWidget *b = group = gtk_radio_button_new (NULL);
3131                 gtk_container_add (GTK_CONTAINER (b), px);
3132         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3133         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3134         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3135         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3136         }
3138         // vertical
3139         {
3140         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3141         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3142                 gtk_container_add (GTK_CONTAINER (b), px);
3143         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3144         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3145         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3146         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3147         }
3149         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3151         // letter spacing
3152     {
3153         {
3154         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3155         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3156         gtk_container_add (GTK_CONTAINER (hb), image);
3157         gtk_widget_show(image);
3158         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3159         }
3160     
3161         {
3162             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3163                                              "tools.text", "letter_spacing", 0.0,
3164                                              us, tbl, FALSE, NULL,
3165                                              -1000.0, 1000.0, 0.1, 0.1,
3166                                              sp_text_letter_changed, 0.1, 1);
3167             gtk_widget_set_size_request (hb, 45, 6);
3168             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3169         }
3170     }
3172         // line spacing
3173     {
3174         {
3175         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3176         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3177         gtk_container_add (GTK_CONTAINER (hb), image);
3178         gtk_widget_show(image);
3179         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3180         }
3181     
3182         {
3183             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3184                                              "tools.text", "line_spacing", 0,
3185                                              us, tbl, FALSE, NULL,
3186                                              -1000.0, 1000.0, 0.1, 0.1,
3187                                              sp_text_line_changed, 0.1, 1);
3188             gtk_widget_set_size_request (hb, 45, 0);
3189             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3190         }
3191     }
3194     // horizontal kerning/vertical kerning units menu: create
3195     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3196     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3197     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3199     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3201     // horizontal kerning
3202     {
3203         {
3204         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3205         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3206         gtk_container_add (GTK_CONTAINER (hb), image);
3207         gtk_widget_show(image);
3208         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3209         }
3211         {
3212             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3213                                              "tools.text", "horizontal_kerning", 0,
3214                                              us, tbl, FALSE, NULL,
3215                                              -100.00, 100.00, 0.01, 0.1,
3216                                              sp_text_horiz_kern_changed);
3217             gtk_widget_set_size_request (hb, 45, 0);
3218             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3219         }
3220     }
3222     // vertical kerning
3223     {
3224         {
3225         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3226         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3227         gtk_container_add (GTK_CONTAINER (hb), image);
3228         gtk_widget_show(image);
3229         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3230         }
3231     
3232         {
3233             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3234                                              "tools.text", "vertical_kerning", 0,
3235                                              us, tbl, FALSE, NULL,
3236                                              -100.00, 100.00, 0.01, 0.1,
3237                                              sp_text_vert_kern_changed);
3238             gtk_widget_set_size_request (hb, 45, 0);
3239             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3240         }
3241     }
3243     // add the units menu
3244     gtk_widget_show(us);
3245     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3246     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3247     }
3249         // letter rotation
3250     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3251     {
3252         {
3253         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3254         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3255         gtk_container_add (GTK_CONTAINER (hb), image);
3256         gtk_widget_show(image);
3257         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3258         }
3259         {
3260             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3261                                              "tools.text", "letter_rotation", 0,
3262                                              us, tbl, FALSE, NULL,
3263                                              -180.0, 180.0, 0.1, 0.1,
3264                                              sp_text_letter_rotation_changed, 0.1, 1);
3265             gtk_widget_set_size_request (hb, 45, 0);
3266             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3267         }
3268         // rotation degree label
3269         {
3270         GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3271         gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3272         }
3273     }
3274         
3275         // Remove Manual Kerns
3276         {
3277         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3278         GtkWidget *button = gtk_button_new ();
3279         gtk_container_add (GTK_CONTAINER (button), px);
3280         gtk_widget_show(button);
3281         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3282         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3283         gtk_widget_set_sensitive(button, TRUE);
3284         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3285         }
3286 #endif
3288         Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
3289         swatch->setWatchedTool ("tools.text", true);
3290         GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
3291         gtk_box_pack_end (GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
3292         gtk_widget_show_all (tbl);
3294         return tbl;
3296     } // end of sp_text_toolbox_new()
3298 }//<unnamed> namespace
3301 //#########################
3302 //##  Connector Toolbox  ##
3303 //#########################
3305 static void sp_connector_path_set_avoid(void)
3307     cc_selection_set_avoid(true);
3311 static void sp_connector_path_set_ignore(void)
3313     cc_selection_set_avoid(false);
3317 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3319     // quit if run by the _changed callbacks
3320     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3321         return;
3322     }
3323         
3324     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3325             "desktop");
3326     SPDocument *doc = sp_desktop_document(desktop);
3328     if (!sp_document_get_undo_sensitive(doc))
3329     {
3330         return;
3331     }
3333     // in turn, prevent callbacks from responding
3334     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3335     
3336     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3337     
3338     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3339     SP_OBJECT(desktop->namedview)->updateRepr();
3340     
3341     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3342     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3343         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3344         NR::Matrix m = NR::identity();
3345         avoid_item_move(&m, item);
3346     }
3348     if (items) {
3349         g_slist_free(items);
3350     }
3351     
3352     sp_document_done(doc);
3354     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3355     
3356     spinbutton_defocus(GTK_OBJECT(tbl));
3360 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3361         gchar const *name, gchar const *old_value, gchar const *new_value,
3362         bool is_interactive, gpointer data)
3364     GtkWidget *tbl = GTK_WIDGET(data);
3366     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3367         return;
3368     }
3369     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3370         return;
3371     }
3373     GtkAdjustment *adj = (GtkAdjustment*)
3374             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3375     gdouble spacing = defaultConnSpacing;
3376     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3377     
3378     gtk_adjustment_set_value(adj, spacing);
3382 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3383     NULL, /* child_added */
3384     NULL, /* child_removed */
3385     connector_tb_event_attr_changed,
3386     NULL, /* content_changed */
3387     NULL  /* order_changed */
3388 };
3391 static GtkWidget *
3392 sp_connector_toolbox_new(SPDesktop *desktop)
3394     GtkTooltips *tt = gtk_tooltips_new();
3395     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3396     
3397     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3398     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3400     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3401             AUX_BETWEEN_BUTTON_GROUPS);
3403     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3404             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3405             tt, _("Make connectors avoid selected objects"));
3407     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3408             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3409             tt, _("Make connectors ignore selected objects"));
3411     //  interval
3412     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3413             AUX_BETWEEN_BUTTON_GROUPS);
3415     // Spacing spinbox
3416     {
3417         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3418                 _("The amount of space left around objects by auto-routing connectors"),
3419                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3420                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3421                 connector_spacing_changed, 1, 0);
3423         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3424                 AUX_SPACING);
3425     }
3427     gtk_widget_show_all(tbl);
3428     sp_set_font_size_smaller (tbl);
3429     
3430     // Code to watch for changes to the connector-spacing attribute in
3431     // the XML.
3432     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3433     g_assert(repr != NULL);
3434         
3435     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3436             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3437     
3438     if (oldrepr) { // remove old listener
3439         sp_repr_remove_listener_by_data(oldrepr, tbl);
3440         Inkscape::GC::release(oldrepr);
3441         oldrepr = NULL;
3442         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3443     }
3445     if (repr) {
3446         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3447         Inkscape::GC::anchor(repr);
3448         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3449         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3450     }
3451     
3452     return tbl;
3454 } // end of sp_connector_toolbox_new()
3457 /*
3458   Local Variables:
3459   mode:c++
3460   c-file-style:"stroustrup"
3461   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3462   indent-tabs-mode:nil
3463   fill-column:99
3464   End:
3465 */
3466 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :