Code

3e37867c8597289c8aa0bad3aadda36baeddffb5
[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>
33 #include <iostream>
34 #include <sstream>
36 #include "widgets/button.h"
37 #include "widgets/widget-sizes.h"
38 #include "widgets/spw-utilities.h"
39 #include "widgets/spinbutton-events.h"
40 #include "dialogs/text-edit.h"
42 #include "ui/widget/style-swatch.h"
44 #include "prefs-utils.h"
45 #include "verbs.h"
46 #include "sp-namedview.h"
47 #include "desktop.h"
48 #include "desktop-handles.h"
49 #include "nodepath.h"
50 #include "xml/repr.h"
51 #include "xml/node-event-vector.h"
52 #include <glibmm/i18n.h>
53 #include "helper/unit-menu.h"
54 #include "helper/units.h"
56 #include "inkscape.h"
57 #include "conn-avoid-ref.h"
60 #include "select-toolbar.h"
61 #include "gradient-toolbar.h"
63 #include "connector-context.h"
64 #include "sp-rect.h"
65 #include "sp-star.h"
66 #include "sp-spiral.h"
67 #include "sp-ellipse.h"
68 #include "sp-text.h"
69 #include "sp-flowtext.h"
70 #include "style.h"
71 #include "selection.h"
72 #include "document-private.h"
73 #include "desktop-style.h"
74 #include "../libnrtype/font-lister.h"
75 #include "../connection-pool.h"
76 #include "../prefs-utils.h"
78 #include "mod360.h"
80 #include "toolbox.h"
82 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
83 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
85 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
86 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
87 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
88 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
89 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
90 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
91 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
92 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
93 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
94 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
95 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
96 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
98 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
101 static struct {
102     gchar const *type_name;
103     gchar const *data_name;
104     sp_verb_t verb;
105     sp_verb_t doubleclick_verb;
106 } const tools[] = {
107     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
108     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
109     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
110     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
111     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
112     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
113     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
114     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
115     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
116     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
117     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
118     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
119     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
120     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
121     { NULL, NULL, 0, 0 }
122 };
124 static struct {
125     gchar const *type_name;
126     gchar const *data_name;
127     GtkWidget *(*create_func)(SPDesktop *desktop);
128 } const aux_toolboxes[] = {
129     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
130     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
131     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
132     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
133     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
134     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
135     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
136     { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
137     { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
138     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
139     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
140     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
141     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
142     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
143     { NULL, NULL, NULL }
144 };
146 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
148 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
149 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
151 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
152 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
154 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
155 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
157 /* Global text entry widgets necessary for update */
158 /* GtkWidget *dropper_rgb_entry, 
159           *dropper_opacity_entry ; */
160 // should be made a private member once this is converted to class
162 static void delete_connection(GObject *obj, sigc::connection *connection) {
163     connection->disconnect();
164     delete connection;
167 static GtkWidget *
168 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
169                       GtkTooltips *tt, gchar const *tip)
171     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
172     gtk_widget_show(b);
173     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
174     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
176     return b;
179 GtkWidget *
180 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
181                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
182                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
184     SPAction *action = verb->get_action(view);
185     if (!action) return NULL;
187     SPAction *doubleclick_action;
188     if (doubleclick_verb)
189         doubleclick_action = doubleclick_verb->get_action(view);
190     else
191         doubleclick_action = NULL;
193     /* fixme: Handle sensitive/unsensitive */
194     /* fixme: Implement sp_button_new_from_action */
195     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
196     gtk_widget_show(b);
197     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
199     return b;
202 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
203                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
205     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
208 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
209                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
211     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
214 GtkWidget *
215 sp_tool_toolbox_new()
217     GtkTooltips *tt = gtk_tooltips_new();
218     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
220     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
221     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
223     gtk_widget_set_sensitive(tb, FALSE);
225     GtkWidget *hb = gtk_handle_box_new();
226     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
227     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
228     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
230     gtk_container_add(GTK_CONTAINER(hb), tb);
231     gtk_widget_show(GTK_WIDGET(tb));
233     sigc::connection* conn = new sigc::connection;
234     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
236     return hb;
239 static void
240 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
242     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
243     gtk_widget_queue_resize(child);
246 static void
247 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
249     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
250     gtk_widget_queue_resize(child);
253 GtkWidget *
254 sp_aux_toolbox_new()
256     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
258     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
259     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
260     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
261     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
262     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
264     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
265     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
267     gtk_widget_set_sensitive(tb, FALSE);
269     GtkWidget *hb = gtk_handle_box_new();
270     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
271     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
272     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
274     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
275     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
277     gtk_container_add(GTK_CONTAINER(hb), tb);
278     gtk_widget_show(GTK_WIDGET(tb));
280     sigc::connection* conn = new sigc::connection;
281     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
283     return hb;
286 //####################################
287 //# Commands Bar
288 //####################################
290 GtkWidget *
291 sp_commands_toolbox_new()
293     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
295     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
296     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
297     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
298     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
299     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
301     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
302     gtk_widget_set_sensitive(tb, FALSE);
304     GtkWidget *hb = gtk_handle_box_new();
305     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
306     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
307     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
309     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
310     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
312     gtk_container_add(GTK_CONTAINER(hb), tb);
313     gtk_widget_show(GTK_WIDGET(tb));
315     sigc::connection* conn = new sigc::connection;
316     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
318     return hb;
322 //####################################
323 //# node editing callbacks
324 //####################################
326 void
327 sp_node_path_edit_add(void)
329     sp_node_selected_add_node();
332 void
333 sp_node_path_edit_delete(void)
335     sp_node_selected_delete();
338 void
339 sp_node_path_edit_delete_segment(void)
341     sp_node_selected_delete_segment();
344 void
345 sp_node_path_edit_break(void)
347     sp_node_selected_break();
350 void
351 sp_node_path_edit_join(void)
353     sp_node_selected_join();
356 void
357 sp_node_path_edit_join_segment(void)
359     sp_node_selected_join_segment();
362 void
363 sp_node_path_edit_toline(void)
365     sp_node_selected_set_line_type(NR_LINETO);
368 void
369 sp_node_path_edit_tocurve(void)
371     sp_node_selected_set_line_type(NR_CURVETO);
374 void
375 sp_node_path_edit_cusp(void)
377     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
380 void
381 sp_node_path_edit_smooth(void)
383     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
386 void
387 sp_node_path_edit_symmetrical(void)
389     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
392 static void toggle_show_handles (GtkWidget *button, gpointer data) {
393     bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
394     prefs_set_int_attribute ("tools.nodes", "show_handles",  show ? 1 : 0);
395     sp_nodepath_show_handles(show);
398 //################################
399 //##    Node Editing Toolbox    ##
400 //################################
402 static GtkWidget *
403 sp_node_toolbox_new(SPDesktop *desktop)
405     Inkscape::UI::View::View *view = desktop;
407     GtkTooltips *tt = gtk_tooltips_new();
408     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
410     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
412     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
413         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
414     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
415         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
417     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
419     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
420         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
421     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
422         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
424     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
425         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
427     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
428         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
430     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
432     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
433         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
435     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
436         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
438     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
439         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
441     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
443     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
444         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
446     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
447         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
449     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
451     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
453     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
455     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
457     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
458     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
460     {
461     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
462                                               SP_BUTTON_TYPE_TOGGLE,
463                                               NULL,
464                                               "nodes_show_handles",
465                                               _("Show the Bezier handles of selected nodes"),
466                                               tt);
467     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
468     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
469     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
470     }
472     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
473     gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
475     gtk_widget_show_all(tb);
477     return tb;
479 } // end of sp_node_toolbox_new()
482 //########################
483 //##    Zoom Toolbox    ##
484 //########################
486 static GtkWidget *
487 sp_zoom_toolbox_new(SPDesktop *desktop)
489     Inkscape::UI::View::View *view=desktop;
491     GtkTooltips *tt = gtk_tooltips_new();
492     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
494     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
495                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
497     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_IN), view, tt);
499     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_OUT), view, tt);
501     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
503     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);
505     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);
507     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);
509     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);
511     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
513     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PREV), view, tt);
515     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_NEXT), view, tt);
517     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
519     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);
521     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);
523     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);
525     gtk_widget_show_all(tb);
527     return tb;
529 } // end of sp_zoom_toolbox_new()
531 void
532 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
534     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")));
538 void
539 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
541     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")));
544 void
545 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
547     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")));
550 static void
551 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
553     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
554     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
556     if (old_desktop) {
557         GList *children, *iter;
559         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
560         for ( iter = children ; iter ; iter = iter->next ) {
561             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
562         }
563         g_list_free(children);
564     }
566     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
568     if (desktop) {
569         gtk_widget_set_sensitive(toolbox, TRUE);
570         setup_func(toolbox, desktop);
571         update_func(desktop, desktop->event_context, toolbox);
572         *conn = desktop->connectEventContextChanged 
573             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
574     } else {
575         gtk_widget_set_sensitive(toolbox, FALSE);
576     }
578 } // end of toolbox_set_desktop()
581 static void
582 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
584     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
585     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
586     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
588     for (int i = 0 ; tools[i].type_name ; i++ ) {
589         GtkWidget *button =
590             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
591                                                               SP_BUTTON_TYPE_TOGGLE,
592                                                               Inkscape::Verb::get(tools[i].verb),
593                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
594                                                               desktop,
595                                                               tooltips );
597         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
598                            (gpointer)button );
599     }
603 static void
604 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
606     gchar const *const tname = ( eventcontext
607                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
608                                  : NULL );
609     for (int i = 0 ; tools[i].type_name ; i++ ) {
610         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
611         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
612     }
615 static void
616 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
618     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
620     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
621         GtkWidget *sub_toolbox;
622         if (aux_toolboxes[i].create_func == NULL)
623             sub_toolbox = sp_empty_toolbox_new(desktop);
624         else
625             sub_toolbox = aux_toolboxes[i].create_func(desktop);
627         gtk_size_group_add_widget( grouper, sub_toolbox );
629         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
630         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
631     }
632     g_object_unref( G_OBJECT(grouper) );
635 static void
636 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
638     gchar const *tname = ( eventcontext
639                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
640                            : NULL );
641     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
642         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
643         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
644             gtk_widget_show_all(sub_toolbox);
645             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
646         } else {
647             gtk_widget_hide(sub_toolbox);
648         }
649     }
652 static void
653 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
655     Inkscape::UI::View::View *view = desktop;
657     GtkTooltips *tt = gtk_tooltips_new();
658     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
660     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
661     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
663     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
664     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
665     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
666     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
668     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
670     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
671     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
673     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
675     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
676     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
678     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
680     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
681     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
682     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
684     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
686     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
687     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
688     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
690     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
692     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
693     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
694     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
696     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
698     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
699     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
701     // disabled until we have icons for them:
703     //find
705     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
706     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
708     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
710     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
711     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
712     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
713     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
715     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
717     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
718     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
720     gtk_widget_show_all(tb);
722     gtk_container_add(GTK_CONTAINER(toolbox), tb);
725 static void
726 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
730 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
732     gtk_widget_show(toolbox_toplevel);
733     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
735     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
736     if (!shown_toolbox) {
737         return;
738     }
739     gtk_widget_show(toolbox);
741     // need to show the spacer, or the padding will be off
742     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
743     gtk_widget_show(spacer);
745     gtk_widget_show_all(shown_toolbox);
748 void
749 aux_toolbox_space(GtkWidget *tb, gint space)
751     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
754 static GtkWidget *
755 sp_empty_toolbox_new(SPDesktop *desktop)
757     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
758     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
759     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
761     gtk_widget_show_all(tbl);
762     sp_set_font_size_smaller (tbl);
764     return tbl;
767 // helper UI functions
769 GtkWidget *
770 sp_tb_spinbutton(
771     gchar *label, gchar const *tooltip,
772     gchar const *path, gchar const *data, gdouble def,
773     GtkWidget *us,
774     GtkWidget *tbl,
775     gboolean altx, gchar const *altx_mark,
776     gdouble lower, gdouble upper, gdouble step, gdouble page,
777     void (*callback)(GtkAdjustment *, GtkWidget *),
778     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
780     GtkTooltips *tt = gtk_tooltips_new();
782     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
784     GtkWidget *l = gtk_label_new(label);
785     gtk_widget_show(l);
786     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
787     gtk_container_add(GTK_CONTAINER(hb), l);
789     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
790                                       lower, upper, step, page, page);
791     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
792     if (us)
793         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
795     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
796     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
797     if (altx)
798         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
799     gtk_widget_set_size_request(sb, 
800                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
801                                 AUX_SPINBUTTON_HEIGHT);
802     gtk_widget_show(sb);
803     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
804     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
805     gtk_container_add(GTK_CONTAINER(hb), sb);
806     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
808     return hb;
811 #define MODE_LABEL_WIDTH 70
813 //########################
814 //##       Star         ##
815 //########################
817 static void
818 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
820     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
822     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
823         // do not remember prefs if this call is initiated by an undo change, because undoing object
824         // creation sets bogus values to its attributes before it is deleted
825         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
826     }
828     // quit if run by the attr_changed listener
829     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
830         return;
831     }
833     // in turn, prevent listener from responding
834     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
836     bool modmade = false;
838     Inkscape::Selection *selection = sp_desktop_selection(desktop);
839     GSList const *items = selection->itemList();
840     for (; items != NULL; items = items->next) {
841         if (SP_IS_STAR((SPItem *) items->data)) {
842             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
843             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
844             sp_repr_set_svg_double(repr, "sodipodi:arg2",
845                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
846                                     + M_PI / (gint)adj->value));
847             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
848             modmade = true;
849         }
850     }
851     if (modmade)  sp_document_done(sp_desktop_document(desktop));
853     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
855     spinbutton_defocus(GTK_OBJECT(tbl));
858 static void
859 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
861     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
863     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
864         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
865     }
867     // quit if run by the attr_changed listener
868     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
869         return;
870     }
872     // in turn, prevent listener from responding
873     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
875     bool modmade = false;
876     Inkscape::Selection *selection = sp_desktop_selection(desktop);
877     GSList const *items = selection->itemList();
878     for (; items != NULL; items = items->next) {
879         if (SP_IS_STAR((SPItem *) items->data)) {
880             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
882             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
883             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
884             if (r2 < r1) {
885                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
886             } else {
887                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
888             }
890             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
891             modmade = true;
892         }
893     }
895     if (modmade) sp_document_done(sp_desktop_document(desktop));
897     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
899     spinbutton_defocus(GTK_OBJECT(tbl));
902 static void
903 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
905     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
907     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
908         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
909             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
910         } else {
911             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
912         }
913     }
915     // quit if run by the attr_changed listener
916     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
917         return;
918     }
920     // in turn, prevent listener from responding
921     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
923     Inkscape::Selection *selection = sp_desktop_selection(desktop);
924     GSList const *items = selection->itemList();
925     GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
926     bool modmade = false;
927     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
928         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
929         for (; items != NULL; items = items->next) {
930             if (SP_IS_STAR((SPItem *) items->data)) {
931                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
932                 repr->setAttribute("inkscape:flatsided", "true");
933                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
934                 modmade = true;
935             }
936         }
937     } else {
938         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
939         for (; items != NULL; items = items->next) {
940             if (SP_IS_STAR((SPItem *) items->data)) {
941                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
942                 repr->setAttribute("inkscape:flatsided", "false");
943                 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
944                 modmade = true;
945             }
946         }
947     }
948     if (modmade) sp_document_done(sp_desktop_document(desktop));
950     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
952     spinbutton_defocus(GTK_OBJECT(tbl));
955 static void
956 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
958     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
960     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
961         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
962     }
964     // quit if run by the attr_changed listener
965     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
966         return;
967     }
969     // in turn, prevent listener from responding
970     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
972     bool modmade = false;
974     Inkscape::Selection *selection = sp_desktop_selection(desktop);
975     GSList const *items = selection->itemList();
976     for (; items != NULL; items = items->next) {
977         if (SP_IS_STAR((SPItem *) items->data)) {
978             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
979             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
980             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
981             modmade = true;
982         }
983     }
984     if (modmade)  sp_document_done(sp_desktop_document(desktop));
986     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
988     spinbutton_defocus(GTK_OBJECT(tbl));
992 static void
993 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
995     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
997     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
998         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
999     }
1001     // quit if run by the attr_changed listener
1002     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1003         return;
1004     }
1006     // in turn, prevent listener from responding
1007     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1009     bool modmade = false;
1011     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1012     GSList const *items = selection->itemList();
1013     for (; items != NULL; items = items->next) {
1014         if (SP_IS_STAR((SPItem *) items->data)) {
1015             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1016             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1017             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1018             modmade = true;
1019         }
1020     }
1021     if (modmade)  sp_document_done(sp_desktop_document(desktop));
1023     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1025     spinbutton_defocus(GTK_OBJECT(tbl));
1029 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1030                                        gchar const *old_value, gchar const *new_value,
1031                                        bool is_interactive, gpointer data)
1033     GtkWidget *tbl = GTK_WIDGET(data);
1035     // quit if run by the _changed callbacks
1036     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1037         return;
1038     }
1040     // in turn, prevent callbacks from responding
1041     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1043     GtkAdjustment *adj;
1045     if (!strcmp(name, "inkscape:randomized")) {
1046         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1047         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1048     } else if (!strcmp(name, "inkscape:rounded")) {
1049         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1050         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1051     } else if (!strcmp(name, "inkscape:flatsided")) {
1052         GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1053         GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1054         char const *flatsides = repr->attribute("inkscape:flatsided");
1055         if (flatsides && !strcmp(flatsides,"false" )) {
1056             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1057             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1058         } else {
1059             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1060             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1061         }
1062     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1063         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1064         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1065         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1066         if (r2 < r1) {
1067             gtk_adjustment_set_value(adj, r2/r1);
1068         } else {
1069             gtk_adjustment_set_value(adj, r1/r2);
1070         }
1071     } else if (!strcmp(name, "sodipodi:sides")) {
1072         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1073         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1074     }
1076     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1080 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1082     NULL, /* child_added */
1083     NULL, /* child_removed */
1084     star_tb_event_attr_changed,
1085     NULL, /* content_changed */
1086     NULL  /* order_changed */
1087 };
1090 /**
1091  *  \param selection Should not be NULL.
1092  */
1093 static void
1094 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1096     int n_selected = 0;
1097     Inkscape::XML::Node *repr = NULL;
1098     Inkscape::XML::Node *oldrepr = NULL;
1100     for (GSList const *items = selection->itemList();
1101          items != NULL;
1102          items = items->next)
1103     {
1104         if (SP_IS_STAR((SPItem *) items->data)) {
1105             n_selected++;
1106             repr = SP_OBJECT_REPR((SPItem *) items->data);
1107         }
1108     }
1110     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1112     if (n_selected == 0) {
1113         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1114     } else if (n_selected == 1) {
1115         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1117         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1118         if (oldrepr) { // remove old listener
1119             sp_repr_remove_listener_by_data(oldrepr, tbl);
1120             Inkscape::GC::release(oldrepr);
1121             oldrepr = 0;
1122             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1123         }
1125         if (repr) {
1126             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1127             Inkscape::GC::anchor(repr);
1128             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1129             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1130         }
1131     } else {
1132         // FIXME: implement averaging of all parameters for multiple selected stars
1133         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1134         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1135     }
1139 static void
1140 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1142     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1143     // callbacks to lump all the changes for all selected objects in one undo step
1145     GtkAdjustment *adj;
1147     // fixme: make settable in prefs!
1148     gint mag = 5;
1149     gdouble prop = 0.5;
1150     gboolean flat = FALSE;
1151     gdouble randomized = 0;
1152     gdouble rounded = 0;
1154     GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1155     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  flat);
1156     GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1157     gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1159     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1160     gtk_adjustment_set_value(adj, mag);
1161     gtk_adjustment_value_changed(adj);
1163     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1164     gtk_adjustment_set_value(adj, prop);
1165     gtk_adjustment_value_changed(adj);
1167     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1168     gtk_adjustment_set_value(adj, rounded);
1169     gtk_adjustment_value_changed(adj);
1171     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1172     gtk_adjustment_set_value(adj, randomized);
1173     gtk_adjustment_value_changed(adj);
1175     spinbutton_defocus(GTK_OBJECT(tbl));
1179 void
1180 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1182     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1183     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1184     GtkWidget *l = gtk_label_new(NULL);
1185     gtk_label_set_markup(GTK_LABEL(l), title);
1186     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1187     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1188     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1192 static GtkWidget *
1193 sp_star_toolbox_new(SPDesktop *desktop)
1195     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1197     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1198     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1200     GtkTooltips *tt = gtk_tooltips_new();
1202     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1204     gchar const *flatsidedstr = NULL;
1206     /* Flatsided checkbox */
1207     {
1208         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1209         GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1210         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1211         flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1212         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1213             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1214         else
1215             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1216         gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1217         gtk_widget_show(fscb);
1218         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1219         gtk_container_add(GTK_CONTAINER(hb), fscb);
1220         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1221         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1222     }
1224     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1226     /* Magnitude */
1227     {
1228         GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1229                                          "tools.shapes.star", "magnitude", 3,
1230                                          NULL, tbl, TRUE, "altx-star",
1231                                          3, 1024, 1, 1,
1232                                          sp_stb_magnitude_value_changed, 1, 0);
1233         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1234     }
1236     /* Spoke ratio */
1237     {
1238         GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1239                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1240                                          // Base radius is the same for the closest handle.
1241                                          _("Base radius to tip radius ratio"),
1242                                          "tools.shapes.star", "proportion", 0.5,
1243                                          NULL, tbl, FALSE, NULL,
1244                                          0.01, 1.0, 0.01, 0.1,
1245                                          sp_stb_proportion_value_changed);
1246         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1247         g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1248         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1249             gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1250         else
1251             gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1252     }
1254     /* Roundedness */
1255     {
1256         GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1257                                          "tools.shapes.star", "rounded", 0.0,
1258                                          NULL, tbl, FALSE, NULL,
1259                                          -100.0, 100.0, 0.01, 0.1,
1260                                          sp_stb_rounded_value_changed);
1261         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1262     }
1264     /* Randomization */
1265     {
1266         GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1267                                          "tools.shapes.star", "randomized", 0.0,
1268                                          NULL, tbl, FALSE, NULL,
1269                                          -10.0, 10.0, 0.001, 0.01,
1270                                          sp_stb_randomized_value_changed, 0.1, 3);
1271         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1272     }
1274     aux_toolbox_space(tbl, AUX_SPACING);
1276     /* Reset */
1277     {
1278         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1279         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1280         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1281         gtk_widget_show(b);
1282         gtk_container_add(GTK_CONTAINER(hb), b);
1283         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1284         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1285     }
1287     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1288     swatch->setWatchedTool ("tools.shapes.star", true);
1289     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1290     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1292     gtk_widget_show_all(tbl);
1293     sp_set_font_size_smaller (tbl);
1295     sigc::connection *connection = new sigc::connection(
1296         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1297         );
1298     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1300     return tbl;
1304 //########################
1305 //##       Rect         ##
1306 //########################
1308 static void 
1309 sp_rtb_sensitivize (GtkWidget *tbl)
1311     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1312     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1313     GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1315     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1316         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1317     } else {
1318         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1319     }
1323 static void
1324 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1325                           void (*setter)(SPRect *, gdouble))
1327     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1329     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1330     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1332     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1333         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1334     }
1336     // quit if run by the attr_changed listener
1337     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1338         return;
1339     }
1341     // in turn, prevent listener from responding
1342     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1344     bool modmade = false;
1345     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1346     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1347         if (SP_IS_RECT(items->data)) {
1348             if (adj->value != 0) {
1349                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1350             } else {
1351                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1352             }
1353             modmade = true;
1354         }
1355     }
1357     sp_rtb_sensitivize (tbl);
1359     if (modmade) {
1360         sp_document_done(sp_desktop_document(desktop));
1361     }
1363     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1365     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1366     spinbutton_defocus(GTK_OBJECT(tbl));
1369 static void
1370 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1372     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1375 static void
1376 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1378     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1381 static void
1382 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1384     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1387 static void
1388 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1390     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1395 static void
1396 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1398     GtkWidget *tbl = GTK_WIDGET(obj);
1400     GtkAdjustment *adj;
1402     adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1403     gtk_adjustment_set_value(adj, 0.0);
1404     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1405     gtk_adjustment_value_changed(adj);
1407     adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1408     gtk_adjustment_set_value(adj, 0.0);
1409     gtk_adjustment_value_changed(adj);
1411     sp_rtb_sensitivize (tbl);
1413     spinbutton_defocus(GTK_OBJECT(tbl));
1416 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1417                                        gchar const *old_value, gchar const *new_value,
1418                                        bool is_interactive, gpointer data)
1420     GtkWidget *tbl = GTK_WIDGET(data);
1422     // quit if run by the _changed callbacks
1423     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1424         return;
1425     }
1427     // in turn, prevent callbacks from responding
1428     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1430     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1431     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1433     SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1434     if (SP_IS_RECT(item)) {
1435         {
1436             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1437             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1438             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1439         }
1441         {
1442             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1443             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1444             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1445         }
1447         {
1448             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1449             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1450             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1451         }
1453         {
1454             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1455             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1456             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1457         }
1458     }
1460     sp_rtb_sensitivize (tbl);
1462     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1466 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1467     NULL, /* child_added */
1468     NULL, /* child_removed */
1469     rect_tb_event_attr_changed,
1470     NULL, /* content_changed */
1471     NULL  /* order_changed */
1472 };
1474 /**
1475  *  \param selection should not be NULL.
1476  */
1477 static void
1478 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1480     int n_selected = 0;
1481     Inkscape::XML::Node *repr = NULL;
1482     SPItem *item = NULL;
1483     Inkscape::XML::Node *oldrepr = NULL;
1485     for (GSList const *items = selection->itemList();
1486          items != NULL;
1487          items = items->next) {
1488         if (SP_IS_RECT((SPItem *) items->data)) {
1489             n_selected++;
1490             item = (SPItem *) items->data;
1491             repr = SP_OBJECT_REPR(item);
1492         }
1493     }
1495     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1497     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1499     if (n_selected == 0) {
1500         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1502         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1503         gtk_widget_set_sensitive(w, FALSE);
1504         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1505         gtk_widget_set_sensitive(h, FALSE);
1507     } else if (n_selected == 1) {
1508         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1509         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1511         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1512         gtk_widget_set_sensitive(w, TRUE);
1513         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1514         gtk_widget_set_sensitive(h, TRUE);
1516         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1517         if (oldrepr) { // remove old listener
1518             sp_repr_remove_listener_by_data(oldrepr, tbl);
1519             Inkscape::GC::release(oldrepr);
1520             oldrepr = 0;
1521             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1522         }
1523         if (repr) {
1524             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1525             g_object_set_data(G_OBJECT(tbl), "item", item);
1526             Inkscape::GC::anchor(repr);
1527             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1528             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1529         }
1530     } else {
1531         // FIXME: implement averaging of all parameters for multiple selected
1532         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1533         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1534         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1535     }
1539 static GtkWidget *
1540 sp_rect_toolbox_new(SPDesktop *desktop)
1542     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1544     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1545     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1547     GtkTooltips *tt = gtk_tooltips_new();
1549     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1551     // rx/ry units menu: create
1552     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1553     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1554     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1555     // fixme: add % meaning per cent of the width/height
1557     /* W */
1558     {
1559         GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1560                                          "tools.shapes.rect", "width", 0,
1561                                          us, tbl, TRUE, "altx-rect",
1562                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1563                                          sp_rtb_width_value_changed);
1564         gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1565         gtk_widget_set_sensitive(hb, FALSE);
1566         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1567     }
1569     /* H */
1570     {
1571         GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1572                                          "tools.shapes.rect", "height", 0,
1573                                          us, tbl, FALSE, NULL,
1574                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1575                                          sp_rtb_height_value_changed);
1576         gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1577         gtk_widget_set_sensitive(hb, FALSE);
1578         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1579     }
1581     /* rx */
1582     {
1583         GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1584                                          "tools.shapes.rect", "rx", 0,
1585                                          us, tbl, FALSE, NULL,
1586                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1587                                          sp_rtb_rx_value_changed);
1588         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1589     }
1591     /* ry */
1592     {
1593         GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1594                                          "tools.shapes.rect", "ry", 0,
1595                                          us, tbl, FALSE, NULL,
1596                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1597                                          sp_rtb_ry_value_changed);
1598         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1599     }
1601     // add the units menu
1602     gtk_widget_show(us);
1603     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1604     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1606     /* Reset */
1607     {
1608         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1609         GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1610         gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1611         gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1612         gtk_widget_show(b);
1613         gtk_container_add(GTK_CONTAINER(hb), b);
1614         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1615         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1616     }
1618     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1619     swatch->setWatchedTool ("tools.shapes.rect", true);
1620     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1621     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1623     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1624     sp_rtb_sensitivize (tbl);
1626     gtk_widget_show_all(tbl);
1627     sp_set_font_size_smaller (tbl);
1629     sigc::connection *connection = new sigc::connection(
1630         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1631         );
1632     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1634     return tbl;
1637 //########################
1638 //##       Spiral       ##
1639 //########################
1641 static void
1642 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1644     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1646     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1647         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1648     }
1650     // quit if run by the attr_changed listener
1651     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1652         return;
1653     }
1655     // in turn, prevent listener from responding
1656     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1658     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1660     bool modmade = false;
1661     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1662          items != NULL;
1663          items = items->next)
1664     {
1665         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1666             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1667             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1668             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1669             modmade = true;
1670         }
1671     }
1673     g_free(namespaced_name);
1675     if (modmade) {
1676         sp_document_done(sp_desktop_document(desktop));
1677     }
1679     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1681     spinbutton_defocus(GTK_OBJECT(tbl));
1684 static void
1685 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1687     sp_spl_tb_value_changed(adj, tbl, "revolution");
1690 static void
1691 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1693     sp_spl_tb_value_changed(adj, tbl, "expansion");
1696 static void
1697 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1699     sp_spl_tb_value_changed(adj, tbl, "t0");
1702 static void
1703 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1705     GtkWidget *tbl = GTK_WIDGET(obj);
1707     GtkAdjustment *adj;
1709     // fixme: make settable
1710     gdouble rev = 5;
1711     gdouble exp = 1.0;
1712     gdouble t0 = 0.0;
1714     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1715     gtk_adjustment_set_value(adj, rev);
1716     gtk_adjustment_value_changed(adj);
1718     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1719     gtk_adjustment_set_value(adj, exp);
1720     gtk_adjustment_value_changed(adj);
1722     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1723     gtk_adjustment_set_value(adj, t0);
1724     gtk_adjustment_value_changed(adj);
1726     spinbutton_defocus(GTK_OBJECT(tbl));
1730 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1731                                          gchar const *old_value, gchar const *new_value,
1732                                          bool is_interactive, gpointer data)
1734     GtkWidget *tbl = GTK_WIDGET(data);
1736     // quit if run by the _changed callbacks
1737     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1738         return;
1739     }
1741     // in turn, prevent callbacks from responding
1742     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1744     GtkAdjustment *adj;
1745     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1746     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1748     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1749     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1751     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1752     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1754     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1758 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1759     NULL, /* child_added */
1760     NULL, /* child_removed */
1761     spiral_tb_event_attr_changed,
1762     NULL, /* content_changed */
1763     NULL  /* order_changed */
1764 };
1766 static void
1767 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1769     int n_selected = 0;
1770     Inkscape::XML::Node *repr = NULL;
1771     Inkscape::XML::Node *oldrepr = NULL;
1773     for (GSList const *items = selection->itemList();
1774          items != NULL;
1775          items = items->next)
1776     {
1777         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1778             n_selected++;
1779             repr = SP_OBJECT_REPR((SPItem *) items->data);
1780         }
1781     }
1783     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1785     if (n_selected == 0) {
1786         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1787     } else if (n_selected == 1) {
1788         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1790         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1791         if (oldrepr) { // remove old listener
1792             sp_repr_remove_listener_by_data(oldrepr, tbl);
1793             Inkscape::GC::release(oldrepr);
1794             oldrepr = 0;
1795             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1796         }
1798         if (repr) {
1799             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1800             Inkscape::GC::anchor(repr);
1801             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1802             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1803         }
1804     } else {
1805         // FIXME: implement averaging of all parameters for multiple selected
1806         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1807         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1808     }
1812 static GtkWidget *
1813 sp_spiral_toolbox_new(SPDesktop *desktop)
1815     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1816     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1817     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1819     GtkTooltips *tt = gtk_tooltips_new();
1821     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1823     /* Revolution */
1824     {
1825         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1826                                          "tools.shapes.spiral", "revolution", 3.0,
1827                                          NULL, tbl, TRUE, "altx-spiral",
1828                                          0.01, 1024.0, 0.1, 1.0,
1829                                          sp_spl_tb_revolution_value_changed, 1, 2);
1830         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1831     }
1833     /* Expansion */
1834     {
1835         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1836                                          "tools.shapes.spiral", "expansion", 1.0,
1837                                          NULL, tbl, FALSE, NULL,
1838                                          0.0, 1000.0, 0.01, 1.0,
1839                                          sp_spl_tb_expansion_value_changed);
1840         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1841     }
1843     /* T0 */
1844     {
1845         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1846                                          "tools.shapes.spiral", "t0", 0.0,
1847                                          NULL, tbl, FALSE, NULL,
1848                                          0.0, 0.999, 0.01, 1.0,
1849                                          sp_spl_tb_t0_value_changed);
1850         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1851     }
1853     aux_toolbox_space(tbl, AUX_SPACING);
1855     /* Reset */
1856     {
1857         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1858         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1859         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1860         gtk_widget_show(b);
1861         gtk_container_add(GTK_CONTAINER(hb), b);
1862         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1863         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1864     }
1866     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1867     swatch->setWatchedTool ("tools.shapes.spiral", true);
1868     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1869     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1871     gtk_widget_show_all(tbl);
1872     sp_set_font_size_smaller (tbl);
1874     sigc::connection *connection = new sigc::connection(
1875         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1876         );
1877     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1879     return tbl;
1882 //########################
1883 //##     Pen/Pencil    ##
1884 //########################
1887 static GtkWidget *
1888 sp_pen_toolbox_new(SPDesktop *desktop)
1890     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1891     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1892     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1894     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1895     swatch->setWatchedTool ("tools.freehand.pen", true);
1896     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1897     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1899     gtk_widget_show_all(tbl);
1900     sp_set_font_size_smaller (tbl);
1902     return tbl;
1905 static GtkWidget *
1906 sp_pencil_toolbox_new(SPDesktop *desktop)
1908     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1909     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1910     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1912     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1913     swatch->setWatchedTool ("tools.freehand.pencil", true);
1914     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1915     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1917     gtk_widget_show_all(tbl);
1918     sp_set_font_size_smaller (tbl);
1920     return tbl;
1924 //########################
1925 //##     Calligraphy    ##
1926 //########################
1928 static void
1929 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1931     prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1932     spinbutton_defocus(GTK_OBJECT(tbl));
1935 static void
1936 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1938     prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1939     spinbutton_defocus(GTK_OBJECT(tbl));
1942 static void
1943 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1945     prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1946     spinbutton_defocus(GTK_OBJECT(tbl));
1949 static void
1950 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1952     prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1953     spinbutton_defocus(GTK_OBJECT(tbl));
1956 static void
1957 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1959     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1960     spinbutton_defocus(GTK_OBJECT(tbl));
1963 static void
1964 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1966     prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1967     spinbutton_defocus(GTK_OBJECT(tbl));
1970 static void
1971 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1973     prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1974     spinbutton_defocus(GTK_OBJECT(tbl));
1977 static void
1978 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1980     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1983 static void
1984 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1986     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1988     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1991 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
1993     // FIXME: make defaults settable via Inkscape Options
1994     struct KeyValue {
1995         char const *key;
1996         double value;
1997     } const key_values[] = {
1998         {"mass", 0.02},
1999         {"drag", 1.0},
2000         {"angle", 30.0},
2001         {"width", 15},
2002         {"thinning", 0.1},
2003         {"tremor", 0.0},
2004         {"flatness", 0.9}
2005     };
2007     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2008         KeyValue const &kv = key_values[i];
2009         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2010         gtk_adjustment_set_value(&adj, kv.value);
2011     }
2013     spinbutton_defocus(GTK_OBJECT(tbl));
2016 static GtkWidget *
2017 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2019     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2020     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2021     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2023     GtkTooltips *tt = gtk_tooltips_new();
2024     GtkWidget *calligraphy_angle;
2026     //  interval
2027     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2029     /* Width */
2030     {
2031         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2032                                          "tools.calligraphic", "width", 15,
2033                                          NULL, tbl, TRUE, "altx-calligraphy",
2034                                          1, 100, 1.0, 10.0,
2035                                          sp_ddc_width_value_changed,  0.01, 0, 100);
2036         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2037     }
2039     /* Thinning */
2040     {
2041         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)"),
2042                                          "tools.calligraphic", "thinning", 0.1,
2043                                          NULL, tbl, FALSE, NULL,
2044                                          -1.0, 1.0, 0.01, 0.1,
2045                                          sp_ddc_velthin_value_changed, 0.01, 2);
2046         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2047     }
2049     //  interval
2050     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2052     /* Angle */
2053     {
2054         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2055                                              "tools.calligraphic", "angle", 30,
2056                                              NULL, tbl, TRUE, "calligraphy-angle",
2057                                              -90.0, 90.0, 1.0, 10.0,
2058                                              sp_ddc_angle_value_changed, 1, 0);
2059         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2060     }
2062     /* Fixation */
2063     {
2064         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2065                                          "tools.calligraphic", "flatness", 0.9,
2066                                          NULL, tbl, FALSE, NULL,
2067                                          0.0, 1.0, 0.01, 0.1,
2068                                          sp_ddc_flatness_value_changed, 0.01, 2);
2069         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2070     }
2072     //  interval
2073     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2075     /* Tremor */
2076     {
2077         GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2078                                          "tools.calligraphic", "tremor", 0.0,
2079                                          NULL, tbl, FALSE, NULL,
2080                                          0.0, 1.0, 0.01, 0.1,
2081                                          sp_ddc_tremor_value_changed, 0.01, 2);
2082         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2083     }
2084     /* Mass */
2085     {
2086         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2087                                          "tools.calligraphic", "mass", 0.02,
2088                                          NULL, tbl, FALSE, NULL,
2089                                          0.0, 1.0, 0.01, 0.1,
2090                                          sp_ddc_mass_value_changed, 0.01, 2);
2091         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2092     }
2094     /* Drag */
2095     {
2096         // TRANSLATORS: "drag" means "resistance" here
2097         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2098                                          "tools.calligraphic", "drag", 1,
2099                                          NULL, tbl, FALSE, NULL,
2100                                          0.0, 1.0, 0.01, 0.1,
2101                                          sp_ddc_drag_value_changed, 0.01, 2);
2102         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2103     }
2105     //  interval
2106     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2108     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2109     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2111     /* Use Pressure button */
2112     {
2113     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2114                                                  SP_BUTTON_TYPE_TOGGLE,
2115                                                  NULL,
2116                                                  "use_pressure",
2117                                                  _("Use the pressure of the input device to alter the width of the pen"),
2118                                                  tt);
2119     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2120     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2121     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2122     }
2124     /* Use Tilt button */
2125     {
2126     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2127                                                  SP_BUTTON_TYPE_TOGGLE,
2128                                                  NULL,
2129                                                  "use_tilt",
2130                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2131                                                  tt);
2132     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2133     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2134     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2135     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2136     }
2138     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2139     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2141     /* Reset */
2142     {
2143         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2144         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2145         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2146         gtk_widget_show(b);
2147         gtk_container_add(GTK_CONTAINER(hb), b);
2148         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2149         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2150     }
2153     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2154     swatch->setWatchedTool ("tools.calligraphic", true);
2155     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2156     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2158     gtk_widget_show_all(tbl);
2159     sp_set_font_size_smaller (tbl);
2161     return tbl;
2165 //########################
2166 //##    Circle / Arc    ##
2167 //########################
2169 static void 
2170 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2172     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2173     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2175     if (v1 == 0 && v2 == 0) {
2176         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2177             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2178             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2179         }
2180     } else {
2181         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2182         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2183     }
2186 static void
2187 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2189     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2191     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2192         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2193     }
2195     // quit if run by the attr_changed listener
2196     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2197         return;
2198     }
2200     // in turn, prevent listener from responding
2201     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2203     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2205     bool modmade = false;
2206     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2207          items != NULL;
2208          items = items->next)
2209     {
2210         SPItem *item = SP_ITEM(items->data);
2212         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2214             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2215             SPArc *arc = SP_ARC(item);
2217             if (!strcmp(value_name, "start"))
2218                 ge->start = (adj->value * M_PI)/ 180;
2219             else
2220                 ge->end = (adj->value * M_PI)/ 180;
2222             sp_genericellipse_normalize(ge);
2223             ((SPObject *)arc)->updateRepr();
2224             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2226             modmade = true;
2227         }
2228     }
2230     g_free(namespaced_name);
2232     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2234     sp_arctb_sensitivize (tbl, adj->value, other->value);
2236     if (modmade) {
2237         sp_document_maybe_done(sp_desktop_document(desktop), value_name);
2238     }
2240     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2241     spinbutton_defocus(GTK_OBJECT(tbl));
2243     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2247 static void
2248 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2250     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2253 static void
2254 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2256     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2259 static void
2260 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2262     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2264     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2265         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2266             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2267         } else {
2268             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2269         }
2270     }
2272     // quit if run by the attr_changed listener
2273     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2274         return;
2275     }
2277     // in turn, prevent listener from responding
2278     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2280     bool modmade = false;
2282     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2283         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2284              items != NULL;
2285              items = items->next)
2286         {
2287             if (SP_IS_ARC((SPItem *) items->data)) {
2288                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2289                 repr->setAttribute("sodipodi:open", "true");
2290                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2291                 modmade = true;
2292             }
2293         }
2294     } else {
2295         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2296              items != NULL;
2297              items = items->next)
2298         {
2299             if (SP_IS_ARC((SPItem *) items->data))    {
2300                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2301                 repr->setAttribute("sodipodi:open", NULL);
2302                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2303                 modmade = true;
2304             }
2305         }
2306     }
2308     if (modmade) {
2309         sp_document_done(sp_desktop_document(desktop));
2310     }
2312     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2314     spinbutton_defocus(GTK_OBJECT(tbl));
2317 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2319     GtkWidget *tbl = GTK_WIDGET(obj);
2321     GtkAdjustment *adj;
2322     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2323     gtk_adjustment_set_value(adj, 0.0);
2324     gtk_adjustment_value_changed(adj);
2326     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2327     gtk_adjustment_set_value(adj, 0.0);
2328     gtk_adjustment_value_changed(adj);
2330     spinbutton_defocus(GTK_OBJECT(tbl));
2333 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2334                                       gchar const *old_value, gchar const *new_value,
2335                                       bool is_interactive, gpointer data)
2337     GtkWidget *tbl = GTK_WIDGET(data);
2339     // quit if run by the _changed callbacks
2340     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2341         return;
2342     }
2344     // in turn, prevent callbacks from responding
2345     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2347     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2348     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2350     GtkAdjustment *adj1,*adj2;
2351     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2352     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2353     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2354     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2356     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2358     char const *openstr = NULL;
2359     openstr = repr->attribute("sodipodi:open");
2360     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2362     if (openstr) {
2363         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2364     } else {
2365         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2366     }
2368     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2371 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2372     NULL, /* child_added */
2373     NULL, /* child_removed */
2374     arc_tb_event_attr_changed,
2375     NULL, /* content_changed */
2376     NULL  /* order_changed */
2377 };
2380 static void
2381 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2383     int n_selected = 0;
2384     Inkscape::XML::Node *repr = NULL;
2385     Inkscape::XML::Node *oldrepr = NULL;
2387     for (GSList const *items = selection->itemList();
2388          items != NULL;
2389          items = items->next)
2390     {
2391         if (SP_IS_ARC((SPItem *) items->data)) {
2392             n_selected++;
2393             repr = SP_OBJECT_REPR((SPItem *) items->data);
2394         }
2395     }
2397     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2399     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2400     if (n_selected == 0) {
2401         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2402     } else if (n_selected == 1) {
2403         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2404         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2406         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2408         if (oldrepr) { // remove old listener
2409             sp_repr_remove_listener_by_data(oldrepr, tbl);
2410             Inkscape::GC::release(oldrepr);
2411             oldrepr = 0;
2412             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2413         }
2415         if (repr) {
2416             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2417             Inkscape::GC::anchor(repr);
2418             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2419             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2420         }
2421     } else {
2422         // FIXME: implement averaging of all parameters for multiple selected
2423         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2424         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2425         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2426     }
2430 static GtkWidget *
2431 sp_arc_toolbox_new(SPDesktop *desktop)
2433     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2435     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2436     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2438     GtkTooltips *tt = gtk_tooltips_new();
2440     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2442     /* Start */
2443     {
2444         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2445                                          "tools.shapes.arc", "start", 0.0,
2446                                          NULL, tbl, TRUE, "altx-arc",
2447                                          -360.0, 360.0, 1.0, 10.0,
2448                                          sp_arctb_start_value_changed);
2449         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2450     }
2452     /* End */
2453     {
2454         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2455                                          "tools.shapes.arc", "end", 0.0,
2456                                          NULL, tbl, FALSE, NULL,
2457                                          -360.0, 360.0, 1.0, 10.0,
2458                                          sp_arctb_end_value_changed);
2459         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2460     }
2462     /* Segments / Pie checkbox */
2463     {
2464         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2465         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2466         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2468         gchar const *openstr = NULL;
2469         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2470         if (!openstr || (openstr && !strcmp(openstr, "false")))
2471             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2472         else
2473             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2475         gtk_widget_show(fscb);
2476         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2477         gtk_container_add(GTK_CONTAINER(hb), fscb);
2478         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2479         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2480     }
2482     /* Make Whole */
2483     {
2484         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2485         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2486         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2487         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2488         gtk_widget_show(b);
2489         gtk_container_add(GTK_CONTAINER(hb), b);
2490         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2491         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2492     }
2494     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2495     // sensitivize make whole and open checkbox
2496     {
2497         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2498         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2499         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2500     }
2502     sigc::connection *connection = new sigc::connection(
2503         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2504         );
2505     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2507     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2508     swatch->setWatchedTool ("tools.shapes.arc", true);
2509     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2510     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2512     gtk_widget_show_all(tbl);
2513     sp_set_font_size_smaller (tbl);
2515     return tbl;
2521 // toggle button callbacks and updaters
2523 //########################
2524 //##      Dropper       ##
2525 //########################
2527 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2528     prefs_set_int_attribute ("tools.dropper", "pick", 
2529         // 0 and 1 are backwards here because of pref
2530         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2534 /**
2535  * Copy the current saved desktop color to the clipboard as full hex + alpha
2536  * color representation. This is useful for passing values between various 
2537  * input boxes, or directly to xml.
2538  */
2539 /* static void
2540 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2542     GtkWidget *tbl = GTK_WIDGET(obj);
2543     
2544     SPDesktop *desktop = 
2545         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2547    
2548     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2549 }*/
2552 /**
2553  * Copies currently saved desktop color to the clipboard as a hex value. This 
2554  * is useful for editing webpages and needing a value quickly for web
2555  * colors.
2556  * 
2557  * TODO: When the toggle of the dropper is set to not mix color against 
2558  *       page background, this still just gets the color of the page and 
2559  *       doesn't get the actual mixed against background which is needed 
2560  *       for the hex value ppl. want for web pages, etc.
2561  */
2563 /* static void
2564 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2566     GtkWidget *tbl = GTK_WIDGET(obj);
2567     
2568     SPDesktop *desktop = 
2569         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2570     
2571     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2572 }*/
2575 /**
2576  * Sets the input boxes with the changed color and opacity. This is used as a 
2577  * callback for style changing.
2578  */
2579 /* static bool
2580 sp_style_changed (const SPCSSAttr *css, gpointer data)
2582     // GrDrag *drag = (GrDrag *) data;
2583     
2584     // set fill of text entry box
2585     if (css->attribute("fill"))
2586         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2587             css->attribute("fill")); 
2589     // set opacity of text entry box
2590     if (css->attribute("fill-opacity"))
2591         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2592             css->attribute("fill-opacity")); 
2593     
2594     // set fill of text entry box
2595     if (css->attribute("stroke"))
2596         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2597             css->attribute("stroke")); 
2599     // set opacity of text entry box
2600     if (css->attribute("stroke-opacity"))
2601         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2602             css->attribute("stroke-opacity"));
2603     return false;
2606 */
2609 /**
2610  * Dropper auxiliary toolbar construction and setup.
2611  *
2612  * TODO: Would like to add swatch of current color.
2613  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2614  *       can drag and drop places. Will provide a nice mixing palette.
2615  */
2616 static GtkWidget *
2617 sp_dropper_toolbox_new(SPDesktop *desktop)
2619     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2621     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2622     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2624     GtkTooltips *tt = gtk_tooltips_new();
2626     
2627     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2628                        AUX_BETWEEN_BUTTON_GROUPS);
2629     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2632     
2633     /* RGB Input Field */
2634  /*   {
2635         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2636         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2637         gtk_widget_show (dropper_rgba_label);
2638         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2639         
2640         dropper_rgb_entry = gtk_entry_new ();
2641         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2642         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2643         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2644         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2645                          _("Hexidecimal representation of last selected "
2646                            "color"), 
2647                          NULL);
2648         gtk_widget_show (dropper_rgb_entry);
2649         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2650         
2651         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2652                            AUX_BETWEEN_BUTTON_GROUPS);
2653     } */
2654     
2655     /* Opacity Input Field */
2656 /*    {
2657         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2658         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2659         gtk_widget_show (dropper_opacity_label);
2660         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2661         
2662         dropper_opacity_entry = gtk_entry_new ();
2663         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2664         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2665         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2666         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2667                          _("Opacity of last selected color"), 
2668                          NULL);
2669         gtk_widget_show (dropper_opacity_entry);
2670         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2671         
2672         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2673                            AUX_BETWEEN_BUTTON_GROUPS);
2674     } */
2675     
2676     
2677     /* Copy to Clipboard */
2678 /*    {
2679         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2680         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2681         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2682                                       "RGB + Alpha (RGBA) to "
2683                                       "clipboard"), 
2684                              NULL);
2685         gtk_widget_show(b);
2686         gtk_container_add(GTK_CONTAINER(hb), b);
2687         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2688             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2689         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2690                            AUX_BETWEEN_BUTTON_GROUPS);
2691     } */
2694     /* Copy to Clipboard as HEX */
2695 /*    {
2696         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2697         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2698         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2699                                       "hexidecimal RGB without alpha " 
2700                                       "to clipboard"), NULL);
2701         gtk_widget_show(b);
2702         gtk_container_add(GTK_CONTAINER(hb), b);
2703         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2704             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2705         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2706                            AUX_BETWEEN_BUTTON_GROUPS);
2707     } */
2708     
2709     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2710     
2711     {
2712         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2713         
2714         GtkWidget *button = 
2715             sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2716                                      SP_BUTTON_TYPE_TOGGLE,
2717                                      NULL,
2718                                      "pick_color",
2719                                      _("When pressed, picks visible color "
2720                                        "without alpha and when not pressed, "
2721                                        "picks color including its "
2722                                        "alpha"),
2723                                      tt);
2725         gtk_widget_show(button);
2726         gtk_container_add (GTK_CONTAINER (hb), button);
2728         g_signal_connect_after (G_OBJECT (button), "clicked", 
2729                                 G_CALLBACK (toggle_dropper_color_pick), NULL);
2730         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2731                                       !prefs_get_int_attribute ("tools.dropper", 
2732                                                                "pick", 0));
2733         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2734                    AUX_BETWEEN_BUTTON_GROUPS);
2735     }
2736    
2737     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2738     
2740     // where new gtkmm stuff should go
2741     
2742     gtk_widget_show_all(tbl);
2743     sp_set_font_size_smaller (tbl);
2745     /*
2746     sigc::connection *connection = new sigc::connection(
2747         desktop->connectSetStyle(
2748             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2749                        desktop)) ); 
2750     
2751     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2752                      connection); */
2753     
2754     return tbl;
2758 //########################
2759 //##    Text Toolbox    ##
2760 //########################
2761 /*
2762 static void
2763 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2765     //Call back for letter sizing spinbutton
2768 static void
2769 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2771     //Call back for line height spinbutton
2774 static void
2775 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2777     //Call back for horizontal kerning spinbutton
2780 static void
2781 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2783     //Call back for vertical kerning spinbutton
2786 static void
2787 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2789     //Call back for letter rotation spinbutton
2790 }*/
2792 namespace {
2794     bool visible = false;
2796     void
2797     sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2798     {
2799         SPStyle *query =
2800             sp_style_new ();
2802         int result_family =
2803             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); 
2805         int result_style =
2806             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); 
2808         int result_numbers =
2809             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2811         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2813         // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2814         if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2815         {
2816             Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
2818             if (repr)
2819             {
2820                 sp_style_read_from_repr (query, repr);
2821             }
2822             else
2823             {
2824                 return;
2825             }
2826         }
2828         if (result_numbers == QUERY_STYLE_MULTIPLE_DIFFERENT)
2829         {
2830             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
2831             gtk_entry_set_text (GTK_ENTRY (entry), "");
2832             return;
2833         }
2835         if (query->text)
2836         {
2837             if (query->text->font_family.value) 
2838             {
2839                 Gtk::TreePath path;
2840                 try {
2841                     path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2842                 } catch (...) {
2843                     return;
2844                 }
2846                 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
2847                 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
2849                 g_object_set_data (G_OBJECT (selection), "block", gpointer(1)); 
2851                 gtk_tree_selection_select_path (selection, path.gobj());
2852                 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
2854                 g_object_set_data (G_OBJECT (selection), "block", gpointer(0)); 
2855             }
2857             //Size
2858             GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
2859             char *str = g_strdup_printf ("%.5g", query->font_size.computed);
2860             g_object_set_data (tbl, "size-block", gpointer(1)); 
2861             gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
2862             g_object_set_data (tbl, "size-block", gpointer(0)); 
2863             free (str);
2865             //Anchor
2866             if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
2867             {
2868                     GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
2869                     g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2870                     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2871                     g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2872             }
2873             else
2874             {
2875                 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
2876                 {
2877                     GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
2878                     g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2879                     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2880                     g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2881                 }
2882                 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
2883                 {
2884                     GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
2885                     g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2886                     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2887                     g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2888                 }
2889                 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
2890                 {
2891                     GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
2892                     g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2893                     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2894                     g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2895                 }
2896             }
2898         }
2899     }
2901     void
2902     sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl) 
2903     {
2904         sp_text_toolbox_selection_changed (selection, tbl); 
2905     }
2907     void
2908     sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
2909     {
2910         sp_text_toolbox_selection_changed (NULL, tbl); 
2911     }
2913     void
2914     sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
2915                                     GObject             *tbl) 
2916     {
2917         SPDesktop    *desktop = SP_ACTIVE_DESKTOP;
2918         GtkTreeModel *model;
2919         GtkWidget    *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
2920         GtkWidget    *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
2921         GtkTreeIter   iter;
2922         char         *family;
2924         gtk_tree_selection_get_selected (selection, &model, &iter);
2925         gtk_tree_model_get (model, &iter, 0, &family, -1);
2927         if (g_object_get_data (G_OBJECT (selection), "block"))
2928         {
2929             gtk_entry_set_text (GTK_ENTRY (entry), family);
2930             return;
2931         }
2932         
2933         gtk_widget_hide (popdown);
2934         visible = false;
2936         gtk_entry_set_text (GTK_ENTRY (entry), family);
2938         SPStyle *query =
2939             sp_style_new ();
2941         int result_numbers =
2942             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2944         SPCSSAttr *css = sp_repr_css_attr_new (); 
2945         sp_repr_css_set_property (css, "font-family", family); 
2947         // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2948         if (result_numbers == QUERY_STYLE_NOTHING)
2949         {
2950             sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
2951             sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
2952         }
2953         else
2954         {
2955             sp_desktop_set_style (desktop, css, true, true);
2956         }
2958         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2959         sp_repr_css_attr_unref (css);
2962         free (family);
2964         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2965     }
2967     void
2968     sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
2969                                            GObject      *tbl) 
2970     {
2971         const char   *family;
2973         family = gtk_entry_get_text (entry);
2975         try {    
2976             Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
2977             GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
2978             GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
2979             gtk_tree_selection_select_path (selection, path.gobj());
2980             gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
2981             gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2982         } catch (...) {
2983             //XXX: Accept it anyway and show the warning
2984             if (family && strlen (family))
2985             {
2986                 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
2987             }
2988        }
2989     }
2991     void
2992     sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
2993                                        gpointer          data)
2994     {
2995         if (g_object_get_data (G_OBJECT (button), "block")) return;
2996         if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
2997         int prop = GPOINTER_TO_INT(data); 
2999         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3000         SPCSSAttr *css = sp_repr_css_attr_new (); 
3002         switch (prop)
3003         {
3004             case 0:
3005             {
3006                 sp_repr_css_set_property (css, "text-anchor", "start"); 
3007                 sp_repr_css_set_property (css, "text-align", "start"); 
3008                 break;
3009             }
3010             case 1:
3011             {
3012                 sp_repr_css_set_property (css, "text-anchor", "middle"); 
3013                 sp_repr_css_set_property (css, "text-align", "center"); 
3014                 break;
3015             }
3017             case 2:
3018             {
3019                 sp_repr_css_set_property (css, "text-anchor", "end"); 
3020                 sp_repr_css_set_property (css, "text-align", "end"); 
3021                 break;
3022             }
3024             case 3:
3025             {
3026                 sp_repr_css_set_property (css, "text-anchor", "start"); 
3027                 sp_repr_css_set_property (css, "text-align", "justify"); 
3028                 break;
3029             }
3030         }
3032         sp_desktop_set_style (desktop, css, true, true);
3033         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
3034         sp_repr_css_attr_unref (css);
3035     }
3037     void
3038     sp_text_toolbox_size_changed  (GtkComboBox *cbox,
3039                                    GObject     *tbl) 
3040     {
3041         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3043         if (g_object_get_data (tbl, "size-block")) return;
3044         if (gtk_combo_box_get_active (cbox) < 0 )  return;
3045     
3046         SPCSSAttr *css = sp_repr_css_attr_new (); 
3047         char *text = gtk_combo_box_get_active_text (cbox);
3048         sp_repr_css_set_property (css, "font-size", text); 
3049         free (text);
3050         sp_desktop_set_style (desktop, css, true, true);
3051         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
3052         sp_repr_css_attr_unref (css);
3053     }
3055 #if 0
3056     void
3057     sp_text_toolbox_style_changed (GtkComboBox *cbox,
3058                                    GtkWidget   *tbl) 
3059     {
3060         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3062         if (GPOINTER_TO_INT(g_object_get_data (G_OBJECT (cbox), "block")) != 0) return;
3063     
3064         static char* styles[] = { "normal", "italic" , "oblique" };
3066         SPCSSAttr *css = sp_repr_css_attr_new (); 
3067         sp_repr_css_set_property (css, "font-style", styles[gtk_combo_box_get_active (cbox)]);
3068         sp_desktop_set_style (desktop, css, true, true);
3069         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
3070         sp_repr_css_attr_unref (css);
3071     }
3072 #endif
3074     void
3075     sp_text_toolbox_text_popdown_clicked    (GtkButton          *button,
3076                                              GObject            *tbl)
3077     {
3078         GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3079         GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3080         int x, y;
3082         if (!visible)
3083         {
3084             gdk_window_get_origin (widget->window, &x, &y);
3085             gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space 
3086             gtk_widget_show_all (popdown);
3087             visible = true;
3088         }
3089         else
3090         {
3091             gtk_widget_hide (popdown);
3092             visible = false;
3093         }
3094     }
3096     gboolean
3097     sp_text_toolbox_entry_focus_in  (GtkWidget        *entry,
3098                                      GdkEventFocus    *event,
3099                                      GObject          *tbl)
3100     {
3101         gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3102         return FALSE;
3103     }
3105     gboolean
3106     sp_text_toolbox_popdown_focus_out (GtkWidget        *popdown,
3107                                        GdkEventFocus    *event,
3108                                        GObject          *tbl)
3109     {
3110         gtk_widget_hide (popdown);
3111         visible = false;
3112         return FALSE;
3113     }
3115     void
3116     cell_data_func  (GtkTreeViewColumn *column,
3117                  GtkCellRenderer   *cell,
3118                  GtkTreeModel      *tree_model,
3119                  GtkTreeIter       *iter,
3120                  gpointer           data)
3121     {
3122         char        *family,
3123                     *family_escaped,
3124                     *sample_escaped;
3126         const char  *sample; 
3127    
3128         gtk_tree_model_get (tree_model, iter, 0, &family, -1); 
3130         sample = prefs_get_string_attribute ("tools.text", "font_sample"); 
3132         family_escaped = g_markup_escape_text (family, -1);
3133         sample_escaped = g_markup_escape_text (sample, -1);
3134     
3135         std::stringstream markup; 
3136         markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3137         g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3139         free (family);
3140         free (family_escaped);
3141         free (sample_escaped);
3142     }
3144     GtkWidget*
3145     sp_text_toolbox_new (SPDesktop *desktop)
3146     {
3147 #if 0
3148         GtkWidget   *us = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "units"));
3149         GtkTooltips *tt = gtk_tooltips_new();
3150         GtkWidget   *group;
3151 #endif
3153         GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
3154         Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3156         ////////////Family
3157         //Window
3158         GtkWidget   *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3159         gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3161         //Entry
3162         GtkWidget           *entry = gtk_entry_new ();
3163         GtkEntryCompletion  *completion = gtk_entry_completion_new ();
3164         gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3165         gtk_entry_completion_set_text_column (completion, 0);
3166         gtk_entry_completion_set_minimum_key_length (completion, 3); //3 characters minimum sounds reasonable
3167         g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3168         gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3169         aux_toolbox_space (tbl, 1);
3170         gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3171         
3172         //Button
3173         GtkWidget   *button = gtk_button_new ();
3174         gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3176         aux_toolbox_space (tbl, 1);
3177         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3179         //Popdown
3180         GtkWidget           *sw = gtk_scrolled_window_new (NULL, NULL);
3181         GtkWidget           *treeview = gtk_tree_view_new ();
3182         GtkCellRenderer     *cell = gtk_cell_renderer_text_new ();
3183         GtkTreeViewColumn   *column = gtk_tree_view_column_new ();
3185         gtk_tree_view_column_pack_start (column, cell, FALSE);
3186         gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3187         gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), tbl, NULL);
3188         g_object_set (G_OBJECT (column), "min-width", int (300), "max-width", int (300), NULL);
3190         gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3191         gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3192         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3193         gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3195         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); 
3196         gtk_container_add (GTK_CONTAINER (sw), treeview);
3198         gtk_container_add (GTK_CONTAINER (window), sw);
3199         gtk_widget_set_size_request (window, 300, 450);
3201         g_signal_connect (G_OBJECT (entry),  "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3202         g_signal_connect (G_OBJECT (entry),  "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3204         g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3206         g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3208         GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3209         g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3211         g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3212         g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3213         g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3214         g_object_set_data (G_OBJECT (tbl), "family-tree-selection", selection);
3215         g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3217         GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3218         aux_toolbox_space (tbl, 1);
3219         GtkWidget *box = gtk_event_box_new ();
3220         gtk_container_add (GTK_CONTAINER (box), image);
3221         gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3222         g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3223         GtkTooltips *tooltips = gtk_tooltips_new ();
3224         gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3225         gtk_widget_hide (GTK_WIDGET (box));
3226         g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3228         ////////////Size
3229         aux_toolbox_space (tbl, 1);
3230         //Cbox
3231         const char *sizes[] = {
3232             "4", "6", "8", "9", "10", "11", "12", "13", "14",
3233             "16", "18", "20", "22", "24", "28",
3234             "32", "36", "40", "48", "56", "64", "72", "144"
3235         };
3237         GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3238         for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3239         gtk_widget_set_size_request (cbox, 80, -1);
3240         aux_toolbox_space (tbl, 1);
3241         gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3242         g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3243         g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3245         ////////////Text anchor
3246         aux_toolbox_space (tbl, 1);
3247         GtkWidget *group   = gtk_radio_button_new (NULL);
3248         GtkWidget *row     = gtk_hbox_new (FALSE, 4);
3249         g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3251         // left
3252         GtkWidget *rbutton = group;
3253         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3254         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3255         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3257         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3258         g_object_set_data   (G_OBJECT (tbl), "text-start", rbutton);
3259         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3261         // center
3262         rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3263         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3264         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3265         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3267         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3268         g_object_set_data   (G_OBJECT (tbl), "text-middle", rbutton);
3269         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1)); 
3271         // right
3272         rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3273         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3274         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3275         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3277         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3278         g_object_set_data   (G_OBJECT (tbl), "text-end", rbutton);
3279         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3281         // fill
3282         rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3283         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3284         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3285         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3287         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3288         g_object_set_data   (G_OBJECT (tbl), "text-fill", rbutton);
3289         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3293         aux_toolbox_space (tbl, 1);
3294         gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3298         Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3300         sigc::connection *c_selection_changed =
3301             new sigc::connection (sp_desktop_selection (desktop)->connectChanged 
3302                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3303         pool->add_connection ("selection-changed", c_selection_changed);
3305         sigc::connection *c_selection_modified =
3306             new sigc::connection (sp_desktop_selection (desktop)->connectModified 
3307                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3308         pool->add_connection ("selection-modified", c_selection_modified);
3310         sigc::connection *c_subselection_changed =
3311             new sigc::connection (desktop->connectToolSubselectionChanged
3312                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3313         pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3315         Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3318 #if 0
3319     //Font Size
3320     GtkWidget *cbox = gtk_combo_box_entry_new ();
3321     aux_toolbox_space(tbl, 1);
3322     gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
3324     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3325     //Bold
3326     {
3327             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3328             GtkWidget *button = gtk_toggle_button_new ();
3329             gtk_container_add (GTK_CONTAINER (button), px);
3330             gtk_widget_show(button);
3331             gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
3332             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3333             gtk_widget_set_sensitive(button, TRUE);
3334             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3335     }
3338         //Italic
3339         {
3340             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3341             GtkWidget *button = gtk_toggle_button_new ();
3342             gtk_container_add (GTK_CONTAINER (button), px);
3343             gtk_widget_show(button);
3344             gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
3345             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3346             gtk_widget_set_sensitive(button, TRUE);
3347             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3348         }
3350         //Underline
3351         {
3352             GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3353             GtkWidget *button = gtk_toggle_button_new ();
3354             gtk_container_add (GTK_CONTAINER (button), px);
3355             gtk_widget_show(button);
3356             gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
3357             gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3358             gtk_widget_set_sensitive(button, FALSE);
3359             gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3360         }
3362         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3363         // align left
3364         {
3365             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3366             GtkWidget *b = group = gtk_radio_button_new (NULL);
3367                 gtk_container_add (GTK_CONTAINER (b), px);
3368             gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
3369             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3370             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3371             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3372         }
3374         // align center
3375         {
3376             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3377             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3378                 gtk_container_add (GTK_CONTAINER (b), px);
3379             // TRANSLATORS: `Center' here is a verb.
3380             gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
3381                 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3382             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3383             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3384         }
3386         // align right
3387         {
3388             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3389             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3390                 gtk_container_add (GTK_CONTAINER (b), px);
3391             gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
3392             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3393             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3394             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3395         }
3397         // full justification
3398         {
3399             GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
3400             GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3401                 gtk_container_add (GTK_CONTAINER (b), px);
3402             gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
3403             gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3404             gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3405             gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3406         }
3407         
3408                 
3409         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3410                 
3411         // horizontal
3412         {
3413         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3414         GtkWidget *b = group = gtk_radio_button_new (NULL);
3415                 gtk_container_add (GTK_CONTAINER (b), px);
3416         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3417         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3418         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3419         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3420         }
3422         // vertical
3423         {
3424         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3425         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3426                 gtk_container_add (GTK_CONTAINER (b), px);
3427         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3428         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3429         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3430         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3431         }
3433         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3435         // letter spacing
3436     {
3437         {
3438         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3439         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3440         gtk_container_add (GTK_CONTAINER (hb), image);
3441         gtk_widget_show(image);
3442         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3443         }
3444     
3445         {
3446             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3447                                              "tools.text", "letter_spacing", 0.0,
3448                                              us, tbl, FALSE, NULL,
3449                                              -1000.0, 1000.0, 0.1, 0.1,
3450                                              sp_text_letter_changed, 0.1, 1);
3451             gtk_widget_set_size_request (hb, 45, 6);
3452             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3453         }
3454     }
3456         // line spacing
3457     {
3458         {
3459         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3460         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3461         gtk_container_add (GTK_CONTAINER (hb), image);
3462         gtk_widget_show(image);
3463         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3464         }
3465     
3466         {
3467             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3468                                              "tools.text", "line_spacing", 0,
3469                                              us, tbl, FALSE, NULL,
3470                                              -1000.0, 1000.0, 0.1, 0.1,
3471                                              sp_text_line_changed, 0.1, 1);
3472             gtk_widget_set_size_request (hb, 45, 0);
3473             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3474         }
3475     }
3478     // horizontal kerning/vertical kerning units menu: create
3479     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3480     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3481     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3483     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3485     // horizontal kerning
3486     {
3487         {
3488         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3489         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3490         gtk_container_add (GTK_CONTAINER (hb), image);
3491         gtk_widget_show(image);
3492         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3493         }
3495         {
3496             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3497                                              "tools.text", "horizontal_kerning", 0,
3498                                              us, tbl, FALSE, NULL,
3499                                              -100.00, 100.00, 0.01, 0.1,
3500                                              sp_text_horiz_kern_changed);
3501             gtk_widget_set_size_request (hb, 45, 0);
3502             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3503         }
3504     }
3506     // vertical kerning
3507     {
3508         {
3509         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3510         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3511         gtk_container_add (GTK_CONTAINER (hb), image);
3512         gtk_widget_show(image);
3513         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3514         }
3515     
3516         {
3517             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3518                                              "tools.text", "vertical_kerning", 0,
3519                                              us, tbl, FALSE, NULL,
3520                                              -100.00, 100.00, 0.01, 0.1,
3521                                              sp_text_vert_kern_changed);
3522             gtk_widget_set_size_request (hb, 45, 0);
3523             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3524         }
3525     }
3527     // add the units menu
3528     gtk_widget_show(us);
3529     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3530     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3531     }
3533         // letter rotation
3534     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3535     {
3536         {
3537         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3538         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3539         gtk_container_add (GTK_CONTAINER (hb), image);
3540         gtk_widget_show(image);
3541         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3542         }
3543         {
3544             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3545                                              "tools.text", "letter_rotation", 0,
3546                                              us, tbl, FALSE, NULL,
3547                                              -180.0, 180.0, 0.1, 0.1,
3548                                              sp_text_letter_rotation_changed, 0.1, 1);
3549             gtk_widget_set_size_request (hb, 45, 0);
3550             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3551         }
3552         // rotation degree label
3553         {
3554         GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3555         gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3556         }
3557     }
3558         
3559         // Remove Manual Kerns
3560         {
3561         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3562         GtkWidget *button = gtk_button_new ();
3563         gtk_container_add (GTK_CONTAINER (button), px);
3564         gtk_widget_show(button);
3565         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3566         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3567         gtk_widget_set_sensitive(button, TRUE);
3568         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3569         }
3570 #endif
3572         gtk_widget_show_all (tbl);
3573         return tbl;
3575     } // end of sp_text_toolbox_new()
3577 }//<unnamed> namespace
3580 //#########################
3581 //##  Connector Toolbox  ##
3582 //#########################
3584 static void sp_connector_path_set_avoid(void)
3586     cc_selection_set_avoid(true);
3590 static void sp_connector_path_set_ignore(void)
3592     cc_selection_set_avoid(false);
3596 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3598     // quit if run by the _changed callbacks
3599     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3600         return;
3601     }
3602         
3603     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3604             "desktop");
3605     SPDocument *doc = sp_desktop_document(desktop);
3607     if (!sp_document_get_undo_sensitive(doc))
3608     {
3609         return;
3610     }
3612     // in turn, prevent callbacks from responding
3613     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3614     
3615     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3616     
3617     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3618     SP_OBJECT(desktop->namedview)->updateRepr();
3619     
3620     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3621     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3622         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3623         NR::Matrix m = NR::identity();
3624         avoid_item_move(&m, item);
3625     }
3627     if (items) {
3628         g_slist_free(items);
3629     }
3630     
3631     sp_document_done(doc);
3633     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3634     
3635     spinbutton_defocus(GTK_OBJECT(tbl));
3639 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3640         gchar const *name, gchar const *old_value, gchar const *new_value,
3641         bool is_interactive, gpointer data)
3643     GtkWidget *tbl = GTK_WIDGET(data);
3645     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3646         return;
3647     }
3648     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3649         return;
3650     }
3652     GtkAdjustment *adj = (GtkAdjustment*)
3653             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3654     gdouble spacing = defaultConnSpacing;
3655     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3656     
3657     gtk_adjustment_set_value(adj, spacing);
3661 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3662     NULL, /* child_added */
3663     NULL, /* child_removed */
3664     connector_tb_event_attr_changed,
3665     NULL, /* content_changed */
3666     NULL  /* order_changed */
3667 };
3670 static GtkWidget *
3671 sp_connector_toolbox_new(SPDesktop *desktop)
3673     GtkTooltips *tt = gtk_tooltips_new();
3674     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3675     
3676     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3677     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3679     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3680             AUX_BETWEEN_BUTTON_GROUPS);
3682     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3683             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3684             tt, _("Make connectors avoid selected objects"));
3686     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3687             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3688             tt, _("Make connectors ignore selected objects"));
3690     //  interval
3691     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3692             AUX_BETWEEN_BUTTON_GROUPS);
3694     // Spacing spinbox
3695     {
3696         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3697                 _("The amount of space left around objects by auto-routing connectors"),
3698                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3699                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3700                 connector_spacing_changed, 1, 0);
3702         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3703                 AUX_SPACING);
3704     }
3706     gtk_widget_show_all(tbl);
3707     sp_set_font_size_smaller (tbl);
3708     
3709     // Code to watch for changes to the connector-spacing attribute in
3710     // the XML.
3711     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3712     g_assert(repr != NULL);
3713         
3714     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3715             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3716     
3717     if (oldrepr) { // remove old listener
3718         sp_repr_remove_listener_by_data(oldrepr, tbl);
3719         Inkscape::GC::release(oldrepr);
3720         oldrepr = NULL;
3721         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3722     }
3724     if (repr) {
3725         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3726         Inkscape::GC::anchor(repr);
3727         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3728         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3729     }
3730     
3731     return tbl;
3733 } // end of sp_connector_toolbox_new()
3736 /*
3737   Local Variables:
3738   mode:c++
3739   c-file-style:"stroustrup"
3740   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3741   indent-tabs-mode:nil
3742   fill-column:99
3743   End:
3744 */
3745 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :