Code

1e19bf871976e6ba8891108b5bbd208a6b0e5ccc
[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             //Style
2899             {
2900                     GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
2902                     gboolean active = gtk_toggle_button_get_active (button);
2903                     gboolean check  = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700); 
2905                     if (active != check) 
2906                     {
2907                         g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2908                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2909                         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2910                     }
2911             }
2913             {
2914                     GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
2916                     gboolean active = gtk_toggle_button_get_active (button);
2917                     gboolean check  = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL); 
2919                     if (active != check)
2920                     {
2921                         g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2922                         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2923                         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2924                     }
2925             }
2927         }
2928     }
2930     void
2931     sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl) 
2932     {
2933         sp_text_toolbox_selection_changed (selection, tbl); 
2934     }
2936     void
2937     sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
2938     {
2939         sp_text_toolbox_selection_changed (NULL, tbl); 
2940     }
2942     void
2943     sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
2944                                     GObject             *tbl) 
2945     {
2946         SPDesktop    *desktop = SP_ACTIVE_DESKTOP;
2947         GtkTreeModel *model;
2948         GtkWidget    *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
2949         GtkWidget    *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
2950         GtkTreeIter   iter;
2951         char         *family;
2953         gtk_tree_selection_get_selected (selection, &model, &iter);
2954         gtk_tree_model_get (model, &iter, 0, &family, -1);
2956         if (g_object_get_data (G_OBJECT (selection), "block"))
2957         {
2958             gtk_entry_set_text (GTK_ENTRY (entry), family);
2959             return;
2960         }
2961         
2962         gtk_widget_hide (popdown);
2963         visible = false;
2965         gtk_entry_set_text (GTK_ENTRY (entry), family);
2967         SPStyle *query =
2968             sp_style_new ();
2970         int result_numbers =
2971             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2973         SPCSSAttr *css = sp_repr_css_attr_new (); 
2974         sp_repr_css_set_property (css, "font-family", family); 
2976         // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2977         if (result_numbers == QUERY_STYLE_NOTHING)
2978         {
2979             sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
2980             sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
2981         }
2982         else
2983         {
2984             sp_desktop_set_style (desktop, css, true, true);
2985         }
2987         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
2988         sp_repr_css_attr_unref (css);
2989         free (family);
2990         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2991     }
2993     void
2994     sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
2995                                            GObject      *tbl) 
2996     {
2997         const char *family = gtk_entry_get_text (entry);
2999         try {    
3000             Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3001             GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3002             GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3003             gtk_tree_selection_select_path (selection, path.gobj());
3004             gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3005             gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
3006         } catch (...) {
3007             if (family && strlen (family))
3008             {
3009                 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3010             }
3011        }
3012     }
3014     void
3015     sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
3016                                        gpointer          data)
3017     {
3018         if (g_object_get_data (G_OBJECT (button), "block")) return;
3019         if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3020         int prop = GPOINTER_TO_INT(data); 
3022         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3023         SPCSSAttr *css = sp_repr_css_attr_new (); 
3025         switch (prop)
3026         {
3027             case 0:
3028             {
3029                 sp_repr_css_set_property (css, "text-anchor", "start"); 
3030                 sp_repr_css_set_property (css, "text-align", "start"); 
3031                 break;
3032             }
3033             case 1:
3034             {
3035                 sp_repr_css_set_property (css, "text-anchor", "middle"); 
3036                 sp_repr_css_set_property (css, "text-align", "center"); 
3037                 break;
3038             }
3040             case 2:
3041             {
3042                 sp_repr_css_set_property (css, "text-anchor", "end"); 
3043                 sp_repr_css_set_property (css, "text-align", "end"); 
3044                 break;
3045             }
3047             case 3:
3048             {
3049                 sp_repr_css_set_property (css, "text-anchor", "start"); 
3050                 sp_repr_css_set_property (css, "text-align", "justify"); 
3051                 break;
3052             }
3053         }
3055         sp_desktop_set_style (desktop, css, true, true);
3056         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
3057         sp_repr_css_attr_unref (css);
3058     }
3060     void
3061     sp_text_toolbox_style_toggled (GtkToggleButton  *button,
3062                                    gpointer          data)
3063     {
3064         if (g_object_get_data (G_OBJECT (button), "block")) return;
3066         SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3067         SPCSSAttr   *css        = sp_repr_css_attr_new (); 
3068         int          prop       = GPOINTER_TO_INT(data); 
3069         bool         active     = gtk_toggle_button_get_active (button);
3072         switch (prop)
3073         {
3074             case 0:
3075             {
3076                 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" ); 
3077                 break;
3078             }
3080             case 1:
3081             {
3082                 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal"); 
3083                 break;
3084             }
3085         }
3087         SPStyle *query =
3088             sp_style_new ();
3089         int result_numbers =
3090             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3092         // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3093         if (result_numbers == QUERY_STYLE_NOTHING)
3094         {
3095             sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3096         }
3097         else
3098         {
3099             sp_desktop_set_style (desktop, css, true, true);
3100         }
3102         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
3103         sp_repr_css_attr_unref (css);
3104     }
3106     void
3107     sp_text_toolbox_size_changed  (GtkComboBox *cbox,
3108                                    GObject     *tbl) 
3109     {
3110         SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3112         if (g_object_get_data (tbl, "size-block")) return;
3113         if (gtk_combo_box_get_active (cbox) < 0 )  return;
3114     
3115         SPCSSAttr *css = sp_repr_css_attr_new (); 
3116         char *text = gtk_combo_box_get_active_text (cbox);
3117         sp_repr_css_set_property (css, "font-size", text); 
3118         free (text);
3120         SPStyle *query =
3121             sp_style_new ();
3122         int result_numbers =
3123             sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3125         // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3126         if (result_numbers == QUERY_STYLE_NOTHING)
3127         {
3128             sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3129         }
3131         sp_desktop_set_style (desktop, css, true, true);
3132         sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP));
3133         sp_repr_css_attr_unref (css);
3134     }
3136     void
3137     sp_text_toolbox_text_popdown_clicked    (GtkButton          *button,
3138                                              GObject            *tbl)
3139     {
3140         GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3141         GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3142         int x, y;
3144         if (!visible)
3145         {
3146             gdk_window_get_origin (widget->window, &x, &y);
3147             gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space 
3148             gtk_widget_show_all (popdown);
3149             visible = true;
3150         }
3151         else
3152         {
3153             gtk_widget_hide (popdown);
3154             visible = false;
3155         }
3156     }
3158     gboolean
3159     sp_text_toolbox_entry_focus_in  (GtkWidget        *entry,
3160                                      GdkEventFocus    *event,
3161                                      GObject          *tbl)
3162     {
3163         gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3164         return FALSE;
3165     }
3167     gboolean
3168     sp_text_toolbox_popdown_focus_out (GtkWidget        *popdown,
3169                                        GdkEventFocus    *event,
3170                                        GObject          *tbl)
3171     {
3172         gtk_widget_hide (popdown);
3173         visible = false;
3174         return FALSE;
3175     }
3177     void
3178     cell_data_func  (GtkTreeViewColumn *column,
3179                  GtkCellRenderer   *cell,
3180                  GtkTreeModel      *tree_model,
3181                  GtkTreeIter       *iter,
3182                  gpointer           data)
3183     {
3184         char        *family,
3185                     *family_escaped,
3186                     *sample_escaped;
3188         const char  *sample; 
3189    
3190         gtk_tree_model_get (tree_model, iter, 0, &family, -1); 
3192         sample = prefs_get_string_attribute ("tools.text", "font_sample"); 
3194         family_escaped = g_markup_escape_text (family, -1);
3195         sample_escaped = g_markup_escape_text (sample, -1);
3196     
3197         std::stringstream markup; 
3198         markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3199         g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3201         free (family);
3202         free (family_escaped);
3203         free (sample_escaped);
3204     }
3206     GtkWidget*
3207     sp_text_toolbox_new (SPDesktop *desktop)
3208     {
3209         GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
3210         Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3212         ////////////Family
3213         //Window
3214         GtkWidget   *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3215         gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3217         //Entry
3218         GtkWidget           *entry = gtk_entry_new ();
3219         GtkEntryCompletion  *completion = gtk_entry_completion_new ();
3220         gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3221         gtk_entry_completion_set_text_column (completion, 0);
3222         gtk_entry_completion_set_minimum_key_length (completion, 3); //3 characters minimum sounds reasonable
3223         g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3224         gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3225         aux_toolbox_space (tbl, 1);
3226         gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3227         
3228         //Button
3229         GtkWidget   *button = gtk_button_new ();
3230         gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3232         aux_toolbox_space (tbl, 1);
3233         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3235         //Popdown
3236         GtkWidget           *sw = gtk_scrolled_window_new (NULL, NULL);
3237         GtkWidget           *treeview = gtk_tree_view_new ();
3238         GtkCellRenderer     *cell = gtk_cell_renderer_text_new ();
3239         GtkTreeViewColumn   *column = gtk_tree_view_column_new ();
3241         gtk_tree_view_column_pack_start (column, cell, FALSE);
3242         gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3243         gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), tbl, NULL);
3244         g_object_set (G_OBJECT (column), "min-width", int (300), "max-width", int (300), NULL);
3246         gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3247         gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3248         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3249         gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3251         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); 
3252         gtk_container_add (GTK_CONTAINER (sw), treeview);
3254         gtk_container_add (GTK_CONTAINER (window), sw);
3255         gtk_widget_set_size_request (window, 300, 450);
3257         g_signal_connect (G_OBJECT (entry),  "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3258         g_signal_connect (G_OBJECT (entry),  "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3260         g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3262         g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3264         GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3265         g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3267         g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3268         g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3269         g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3270         g_object_set_data (G_OBJECT (tbl), "family-tree-selection", selection);
3271         g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3273         GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3274         aux_toolbox_space (tbl, 1);
3275         GtkWidget *box = gtk_event_box_new ();
3276         gtk_container_add (GTK_CONTAINER (box), image);
3277         gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3278         g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3279         GtkTooltips *tooltips = gtk_tooltips_new ();
3280         gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3281         gtk_widget_hide (GTK_WIDGET (box));
3282         g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3284         ////////////Size
3285         aux_toolbox_space (tbl, 1);
3286         //Cbox
3287         const char *sizes[] = {
3288             "4", "6", "8", "9", "10", "11", "12", "13", "14",
3289             "16", "18", "20", "22", "24", "28",
3290             "32", "36", "40", "48", "56", "64", "72", "144"
3291         };
3293         GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3294         for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3295         gtk_widget_set_size_request (cbox, 80, -1);
3296         aux_toolbox_space (tbl, 1);
3297         gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3298         g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3299         g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3301         ////////////Text anchor
3302         aux_toolbox_space (tbl, 1);
3303         GtkWidget *group   = gtk_radio_button_new (NULL);
3304         GtkWidget *row     = gtk_hbox_new (FALSE, 4);
3305         g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3307         // left
3308         GtkWidget *rbutton = group;
3309         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3310         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3311         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3313         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3314         g_object_set_data   (G_OBJECT (tbl), "text-start", rbutton);
3315         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3317         // center
3318         rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3319         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3320         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3321         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3323         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3324         g_object_set_data   (G_OBJECT (tbl), "text-middle", rbutton);
3325         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1)); 
3327         // right
3328         rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3329         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3330         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3331         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3333         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3334         g_object_set_data   (G_OBJECT (tbl), "text-end", rbutton);
3335         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3337         // fill
3338         rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3339         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3340         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3341         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3343         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3344         g_object_set_data   (G_OBJECT (tbl), "text-fill", rbutton);
3345         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3347         aux_toolbox_space (tbl, 1);
3348         gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3350         ////////////Text anchor
3351         aux_toolbox_space (tbl, 1);
3352         row = gtk_hbox_new (FALSE, 4);
3354         // bold 
3355         rbutton = gtk_toggle_button_new (); 
3356         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3357         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3358         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3360         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3361         g_object_set_data   (G_OBJECT (tbl), "style-bold", rbutton);
3362         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3364         // italic
3365         rbutton = gtk_toggle_button_new (); 
3366         gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3367         gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3368         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3370         gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3371         g_object_set_data   (G_OBJECT (tbl), "style-italic", rbutton);
3372         g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1)); 
3374         aux_toolbox_space (tbl, 1);
3375         gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3378         //watch selection
3379         Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3381         sigc::connection *c_selection_changed =
3382             new sigc::connection (sp_desktop_selection (desktop)->connectChanged 
3383                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3384         pool->add_connection ("selection-changed", c_selection_changed);
3386         sigc::connection *c_selection_modified =
3387             new sigc::connection (sp_desktop_selection (desktop)->connectModified 
3388                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3389         pool->add_connection ("selection-modified", c_selection_modified);
3391         sigc::connection *c_subselection_changed =
3392             new sigc::connection (desktop->connectToolSubselectionChanged
3393                                 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3394         pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3396         Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3399 #if 0
3400         // horizontal
3401         {
3402         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3403         GtkWidget *b = group = gtk_radio_button_new (NULL);
3404                 gtk_container_add (GTK_CONTAINER (b), px);
3405         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3406         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3407         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3408         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3409         }
3411         // vertical
3412         {
3413         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3414         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3415                 gtk_container_add (GTK_CONTAINER (b), px);
3416         gtk_tooltips_set_tip (tt, b, _("Vertical 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         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3424         // letter spacing
3425     {
3426         {
3427         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3428         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3429         gtk_container_add (GTK_CONTAINER (hb), image);
3430         gtk_widget_show(image);
3431         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3432         }
3433     
3434         {
3435             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3436                                              "tools.text", "letter_spacing", 0.0,
3437                                              us, tbl, FALSE, NULL,
3438                                              -1000.0, 1000.0, 0.1, 0.1,
3439                                              sp_text_letter_changed, 0.1, 1);
3440             gtk_widget_set_size_request (hb, 45, 6);
3441             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3442         }
3443     }
3445         // line spacing
3446     {
3447         {
3448         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3449         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3450         gtk_container_add (GTK_CONTAINER (hb), image);
3451         gtk_widget_show(image);
3452         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3453         }
3454     
3455         {
3456             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3457                                              "tools.text", "line_spacing", 0,
3458                                              us, tbl, FALSE, NULL,
3459                                              -1000.0, 1000.0, 0.1, 0.1,
3460                                              sp_text_line_changed, 0.1, 1);
3461             gtk_widget_set_size_request (hb, 45, 0);
3462             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3463         }
3464     }
3467     // horizontal kerning/vertical kerning units menu: create
3468     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3469     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3470     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3472     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3474     // horizontal kerning
3475     {
3476         {
3477         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3478         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3479         gtk_container_add (GTK_CONTAINER (hb), image);
3480         gtk_widget_show(image);
3481         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3482         }
3484         {
3485             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3486                                              "tools.text", "horizontal_kerning", 0,
3487                                              us, tbl, FALSE, NULL,
3488                                              -100.00, 100.00, 0.01, 0.1,
3489                                              sp_text_horiz_kern_changed);
3490             gtk_widget_set_size_request (hb, 45, 0);
3491             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3492         }
3493     }
3495     // vertical kerning
3496     {
3497         {
3498         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3499         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3500         gtk_container_add (GTK_CONTAINER (hb), image);
3501         gtk_widget_show(image);
3502         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3503         }
3504     
3505         {
3506             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3507                                              "tools.text", "vertical_kerning", 0,
3508                                              us, tbl, FALSE, NULL,
3509                                              -100.00, 100.00, 0.01, 0.1,
3510                                              sp_text_vert_kern_changed);
3511             gtk_widget_set_size_request (hb, 45, 0);
3512             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3513         }
3514     }
3516     // add the units menu
3517     gtk_widget_show(us);
3518     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3519     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3520     }
3522         // letter rotation
3523     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3524     {
3525         {
3526         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3527         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3528         gtk_container_add (GTK_CONTAINER (hb), image);
3529         gtk_widget_show(image);
3530         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3531         }
3532         {
3533             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3534                                              "tools.text", "letter_rotation", 0,
3535                                              us, tbl, FALSE, NULL,
3536                                              -180.0, 180.0, 0.1, 0.1,
3537                                              sp_text_letter_rotation_changed, 0.1, 1);
3538             gtk_widget_set_size_request (hb, 45, 0);
3539             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3540         }
3541         // rotation degree label
3542         {
3543         GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3544         gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3545         }
3546     }
3547         
3548         // Remove Manual Kerns
3549         {
3550         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3551         GtkWidget *button = gtk_button_new ();
3552         gtk_container_add (GTK_CONTAINER (button), px);
3553         gtk_widget_show(button);
3554         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3555         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3556         gtk_widget_set_sensitive(button, TRUE);
3557         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3558         }
3559 #endif
3561         gtk_widget_show_all (tbl);
3562         return tbl;
3564     } // end of sp_text_toolbox_new()
3566 }//<unnamed> namespace
3569 //#########################
3570 //##  Connector Toolbox  ##
3571 //#########################
3573 static void sp_connector_path_set_avoid(void)
3575     cc_selection_set_avoid(true);
3579 static void sp_connector_path_set_ignore(void)
3581     cc_selection_set_avoid(false);
3585 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3587     // quit if run by the _changed callbacks
3588     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3589         return;
3590     }
3591         
3592     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3593             "desktop");
3594     SPDocument *doc = sp_desktop_document(desktop);
3596     if (!sp_document_get_undo_sensitive(doc))
3597     {
3598         return;
3599     }
3601     // in turn, prevent callbacks from responding
3602     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3603     
3604     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3605     
3606     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3607     SP_OBJECT(desktop->namedview)->updateRepr();
3608     
3609     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3610     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3611         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3612         NR::Matrix m = NR::identity();
3613         avoid_item_move(&m, item);
3614     }
3616     if (items) {
3617         g_slist_free(items);
3618     }
3619     
3620     sp_document_done(doc);
3622     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3623     
3624     spinbutton_defocus(GTK_OBJECT(tbl));
3628 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3629         gchar const *name, gchar const *old_value, gchar const *new_value,
3630         bool is_interactive, gpointer data)
3632     GtkWidget *tbl = GTK_WIDGET(data);
3634     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3635         return;
3636     }
3637     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3638         return;
3639     }
3641     GtkAdjustment *adj = (GtkAdjustment*)
3642             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3643     gdouble spacing = defaultConnSpacing;
3644     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3645     
3646     gtk_adjustment_set_value(adj, spacing);
3650 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3651     NULL, /* child_added */
3652     NULL, /* child_removed */
3653     connector_tb_event_attr_changed,
3654     NULL, /* content_changed */
3655     NULL  /* order_changed */
3656 };
3659 static GtkWidget *
3660 sp_connector_toolbox_new(SPDesktop *desktop)
3662     GtkTooltips *tt = gtk_tooltips_new();
3663     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3664     
3665     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3666     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3668     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3669             AUX_BETWEEN_BUTTON_GROUPS);
3671     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3672             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3673             tt, _("Make connectors avoid selected objects"));
3675     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3676             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3677             tt, _("Make connectors ignore selected objects"));
3679     //  interval
3680     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3681             AUX_BETWEEN_BUTTON_GROUPS);
3683     // Spacing spinbox
3684     {
3685         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3686                 _("The amount of space left around objects by auto-routing connectors"),
3687                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3688                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3689                 connector_spacing_changed, 1, 0);
3691         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3692                 AUX_SPACING);
3693     }
3695     gtk_widget_show_all(tbl);
3696     sp_set_font_size_smaller (tbl);
3697     
3698     // Code to watch for changes to the connector-spacing attribute in
3699     // the XML.
3700     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3701     g_assert(repr != NULL);
3702         
3703     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3704             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3705     
3706     if (oldrepr) { // remove old listener
3707         sp_repr_remove_listener_by_data(oldrepr, tbl);
3708         Inkscape::GC::release(oldrepr);
3709         oldrepr = NULL;
3710         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3711     }
3713     if (repr) {
3714         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3715         Inkscape::GC::anchor(repr);
3716         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3717         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3718     }
3719     
3720     return tbl;
3722 } // end of sp_connector_toolbox_new()
3725 /*
3726   Local Variables:
3727   mode:c++
3728   c-file-style:"stroustrup"
3729   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3730   indent-tabs-mode:nil
3731   fill-column:99
3732   End:
3733 */
3734 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :