Code

d4282bd663ac3afb529f79e09374938b9b348f13
[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"
77 #include "../inkscape-stock.h"
78 #include "icon.h"
79 #include "graphlayout/graphlayout.h"
81 #include "mod360.h"
83 #include "toolbox.h"
85 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
86 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
88 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
89 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
90 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
91 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
92 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
93 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
94 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
95 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
96 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
97 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
98 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
99 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
101 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
104 static struct {
105     gchar const *type_name;
106     gchar const *data_name;
107     sp_verb_t verb;
108     sp_verb_t doubleclick_verb;
109 } const tools[] = {
110     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
111     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
112     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
113     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
114     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
115     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
116     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
117     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
118     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
119     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
120     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
121     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
122     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
123     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
124     { NULL, NULL, 0, 0 }
125 };
127 static struct {
128     gchar const *type_name;
129     gchar const *data_name;
130     GtkWidget *(*create_func)(SPDesktop *desktop);
131 } const aux_toolboxes[] = {
132     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
133     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
134     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
135     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
136     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
137     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
138     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
139     { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
140     { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
141     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
142     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
143     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
144     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
145     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
146     { NULL, NULL, NULL }
147 };
149 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
151 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
152 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
154 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
155 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
157 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
158 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
160 /* Global text entry widgets necessary for update */
161 /* GtkWidget *dropper_rgb_entry, 
162           *dropper_opacity_entry ; */
163 // should be made a private member once this is converted to class
165 static void delete_connection(GObject *obj, sigc::connection *connection) {
166     connection->disconnect();
167     delete connection;
170 static GtkWidget *
171 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
172                       GtkTooltips *tt, gchar const *tip)
174     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
175     gtk_widget_show(b);
176     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
177     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
179     return b;
182 GtkWidget *
183 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
184                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
185                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
187     SPAction *action = verb->get_action(view);
188     if (!action) return NULL;
190     SPAction *doubleclick_action;
191     if (doubleclick_verb)
192         doubleclick_action = doubleclick_verb->get_action(view);
193     else
194         doubleclick_action = NULL;
196     /* fixme: Handle sensitive/unsensitive */
197     /* fixme: Implement sp_button_new_from_action */
198     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
199     gtk_widget_show(b);
200     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
202     return b;
205 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
206                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
208     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
211 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
212                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
214     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
217 GtkWidget *
218 sp_tool_toolbox_new()
220     GtkTooltips *tt = gtk_tooltips_new();
221     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
223     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
224     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
226     gtk_widget_set_sensitive(tb, FALSE);
228     GtkWidget *hb = gtk_handle_box_new();
229     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
230     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
231     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
233     gtk_container_add(GTK_CONTAINER(hb), tb);
234     gtk_widget_show(GTK_WIDGET(tb));
236     sigc::connection* conn = new sigc::connection;
237     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
239     return hb;
242 static void
243 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
245     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
246     gtk_widget_queue_resize(child);
249 static void
250 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
252     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
253     gtk_widget_queue_resize(child);
256 GtkWidget *
257 sp_aux_toolbox_new()
259     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
261     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
262     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
263     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
264     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
265     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
267     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
268     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
270     gtk_widget_set_sensitive(tb, FALSE);
272     GtkWidget *hb = gtk_handle_box_new();
273     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
274     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
275     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
277     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
278     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
280     gtk_container_add(GTK_CONTAINER(hb), tb);
281     gtk_widget_show(GTK_WIDGET(tb));
283     sigc::connection* conn = new sigc::connection;
284     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
286     return hb;
289 //####################################
290 //# Commands Bar
291 //####################################
293 GtkWidget *
294 sp_commands_toolbox_new()
296     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
298     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
299     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
300     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
301     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
302     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
304     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
305     gtk_widget_set_sensitive(tb, FALSE);
307     GtkWidget *hb = gtk_handle_box_new();
308     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
309     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
310     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
312     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
313     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
315     gtk_container_add(GTK_CONTAINER(hb), tb);
316     gtk_widget_show(GTK_WIDGET(tb));
318     sigc::connection* conn = new sigc::connection;
319     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
321     return hb;
325 //####################################
326 //# node editing callbacks
327 //####################################
329 void
330 sp_node_path_edit_add(void)
332     sp_node_selected_add_node();
335 void
336 sp_node_path_edit_delete(void)
338     sp_node_selected_delete();
341 void
342 sp_node_path_edit_delete_segment(void)
344     sp_node_selected_delete_segment();
347 void
348 sp_node_path_edit_break(void)
350     sp_node_selected_break();
353 void
354 sp_node_path_edit_join(void)
356     sp_node_selected_join();
359 void
360 sp_node_path_edit_join_segment(void)
362     sp_node_selected_join_segment();
365 void
366 sp_node_path_edit_toline(void)
368     sp_node_selected_set_line_type(NR_LINETO);
371 void
372 sp_node_path_edit_tocurve(void)
374     sp_node_selected_set_line_type(NR_CURVETO);
377 void
378 sp_node_path_edit_cusp(void)
380     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
383 void
384 sp_node_path_edit_smooth(void)
386     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
389 void
390 sp_node_path_edit_symmetrical(void)
392     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
395 static void toggle_show_handles (GtkWidget *button, gpointer data) {
396     bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
397     prefs_set_int_attribute ("tools.nodes", "show_handles",  show ? 1 : 0);
398     sp_nodepath_show_handles(show);
401 //################################
402 //##    Node Editing Toolbox    ##
403 //################################
405 static GtkWidget *
406 sp_node_toolbox_new(SPDesktop *desktop)
408     Inkscape::UI::View::View *view = desktop;
410     GtkTooltips *tt = gtk_tooltips_new();
411     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
413     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
415     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
416         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
417     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
418         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
420     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
422     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
423         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
424     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
425         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
427     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
428         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
430     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
431         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
433     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
435     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
436         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
438     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
439         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
441     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
442         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
444     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
446     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
447         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
449     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
450         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
452     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
454     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
456     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
458     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
460     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
461     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
463     {
464     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
465                                               SP_BUTTON_TYPE_TOGGLE,
466                                               NULL,
467                                               "nodes_show_handles",
468                                               _("Show the Bezier handles of selected nodes"),
469                                               tt);
470     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
471     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
472     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
473     }
475     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
476     gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
478     gtk_widget_show_all(tb);
480     return tb;
482 } // end of sp_node_toolbox_new()
485 //########################
486 //##    Zoom Toolbox    ##
487 //########################
489 static GtkWidget *
490 sp_zoom_toolbox_new(SPDesktop *desktop)
492     Inkscape::UI::View::View *view=desktop;
494     GtkTooltips *tt = gtk_tooltips_new();
495     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
497     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
498                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
500     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);
502     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);
504     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
506     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);
508     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);
510     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);
512     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);
514     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
516     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);
518     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);
520     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
522     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);
524     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);
526     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);
528     gtk_widget_show_all(tb);
530     return tb;
532 } // end of sp_zoom_toolbox_new()
534 void
535 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
537     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")));
541 void
542 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
544     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")));
547 void
548 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
550     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")));
553 static void
554 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
556     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
557     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
559     if (old_desktop) {
560         GList *children, *iter;
562         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
563         for ( iter = children ; iter ; iter = iter->next ) {
564             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
565         }
566         g_list_free(children);
567     }
569     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
571     if (desktop) {
572         gtk_widget_set_sensitive(toolbox, TRUE);
573         setup_func(toolbox, desktop);
574         update_func(desktop, desktop->event_context, toolbox);
575         *conn = desktop->connectEventContextChanged 
576             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
577     } else {
578         gtk_widget_set_sensitive(toolbox, FALSE);
579     }
581 } // end of toolbox_set_desktop()
584 static void
585 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
587     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
588     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
589     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
591     for (int i = 0 ; tools[i].type_name ; i++ ) {
592         GtkWidget *button =
593             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
594                                                               SP_BUTTON_TYPE_TOGGLE,
595                                                               Inkscape::Verb::get(tools[i].verb),
596                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
597                                                               desktop,
598                                                               tooltips );
600         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
601                            (gpointer)button );
602     }
606 static void
607 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
609     gchar const *const tname = ( eventcontext
610                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
611                                  : NULL );
612     for (int i = 0 ; tools[i].type_name ; i++ ) {
613         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
614         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
615     }
618 static void
619 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
621     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
623     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
624         GtkWidget *sub_toolbox;
625         if (aux_toolboxes[i].create_func == NULL)
626             sub_toolbox = sp_empty_toolbox_new(desktop);
627         else
628             sub_toolbox = aux_toolboxes[i].create_func(desktop);
630         gtk_size_group_add_widget( grouper, sub_toolbox );
632         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
633         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
634     }
635     g_object_unref( G_OBJECT(grouper) );
638 static void
639 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
641     gchar const *tname = ( eventcontext
642                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
643                            : NULL );
644     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
645         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
646         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
647             gtk_widget_show_all(sub_toolbox);
648             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
649         } else {
650             gtk_widget_hide(sub_toolbox);
651         }
652     }
655 static void
656 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
658     Inkscape::UI::View::View *view = desktop;
660     GtkTooltips *tt = gtk_tooltips_new();
661     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
663     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
664     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
666     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
667     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
668     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
669     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
671     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
673     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
674     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
676     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
678     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
679     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
681     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
683     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
684     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
685     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
687     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
689     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
690     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
691     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
693     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
695     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
696     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
697     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
699     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
701     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
702     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
704     // disabled until we have icons for them:
706     //find
708     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
709     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
711     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
713     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
714     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
715     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
716     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
718     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
720     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
721     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
723     gtk_widget_show_all(tb);
725     gtk_container_add(GTK_CONTAINER(toolbox), tb);
728 static void
729 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
733 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
735     gtk_widget_show(toolbox_toplevel);
736     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
738     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
739     if (!shown_toolbox) {
740         return;
741     }
742     gtk_widget_show(toolbox);
744     // need to show the spacer, or the padding will be off
745     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
746     gtk_widget_show(spacer);
748     gtk_widget_show_all(shown_toolbox);
751 void
752 aux_toolbox_space(GtkWidget *tb, gint space)
754     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
757 static GtkWidget *
758 sp_empty_toolbox_new(SPDesktop *desktop)
760     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
761     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
762     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
764     gtk_widget_show_all(tbl);
765     sp_set_font_size_smaller (tbl);
767     return tbl;
770 // helper UI functions
772 GtkWidget *
773 sp_tb_spinbutton(
774     gchar *label, gchar const *tooltip,
775     gchar const *path, gchar const *data, gdouble def,
776     GtkWidget *us,
777     GtkWidget *tbl,
778     gboolean altx, gchar const *altx_mark,
779     gdouble lower, gdouble upper, gdouble step, gdouble page,
780     void (*callback)(GtkAdjustment *, GtkWidget *),
781     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
783     GtkTooltips *tt = gtk_tooltips_new();
785     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
787     GtkWidget *l = gtk_label_new(label);
788     gtk_widget_show(l);
789     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
790     gtk_container_add(GTK_CONTAINER(hb), l);
792     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
793                                       lower, upper, step, page, page);
794     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
795     if (us)
796         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
798     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
799     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
800     if (altx)
801         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
802     gtk_widget_set_size_request(sb, 
803                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
804                                 AUX_SPINBUTTON_HEIGHT);
805     gtk_widget_show(sb);
806     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
807     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
808     gtk_container_add(GTK_CONTAINER(hb), sb);
809     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
811     return hb;
814 #define MODE_LABEL_WIDTH 70
816 //########################
817 //##       Star         ##
818 //########################
820 static void
821 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
823     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
825     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
826         // do not remember prefs if this call is initiated by an undo change, because undoing object
827         // creation sets bogus values to its attributes before it is deleted
828         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
829     }
831     // quit if run by the attr_changed listener
832     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
833         return;
834     }
836     // in turn, prevent listener from responding
837     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
839     bool modmade = false;
841     Inkscape::Selection *selection = sp_desktop_selection(desktop);
842     GSList const *items = selection->itemList();
843     for (; items != NULL; items = items->next) {
844         if (SP_IS_STAR((SPItem *) items->data)) {
845             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
846             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
847             sp_repr_set_svg_double(repr, "sodipodi:arg2",
848                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
849                                     + M_PI / (gint)adj->value));
850             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
851             modmade = true;
852         }
853     }
854     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
855                                    /* TODO: annotate */ "toolbox.cpp:854");
857     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
859     spinbutton_defocus(GTK_OBJECT(tbl));
862 static void
863 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
865     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
867     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
868         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
869     }
871     // quit if run by the attr_changed listener
872     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
873         return;
874     }
876     // in turn, prevent listener from responding
877     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
879     bool modmade = false;
880     Inkscape::Selection *selection = sp_desktop_selection(desktop);
881     GSList const *items = selection->itemList();
882     for (; items != NULL; items = items->next) {
883         if (SP_IS_STAR((SPItem *) items->data)) {
884             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
886             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
887             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
888             if (r2 < r1) {
889                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
890             } else {
891                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
892             }
894             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
895             modmade = true;
896         }
897     }
899     if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
900                                   /* TODO: annotate */ "toolbox.cpp:899");
902     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
904     spinbutton_defocus(GTK_OBJECT(tbl));
907 static void
908 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
910     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
912     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
913         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
914             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
915         } else {
916             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
917         }
918     }
920     // quit if run by the attr_changed listener
921     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
922         return;
923     }
925     // in turn, prevent listener from responding
926     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
928     Inkscape::Selection *selection = sp_desktop_selection(desktop);
929     GSList const *items = selection->itemList();
930     GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
931     bool modmade = false;
932     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
933         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
934         for (; items != NULL; items = items->next) {
935             if (SP_IS_STAR((SPItem *) items->data)) {
936                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
937                 repr->setAttribute("inkscape:flatsided", "true");
938                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
939                 modmade = true;
940             }
941         }
942     } else {
943         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
944         for (; items != NULL; items = items->next) {
945             if (SP_IS_STAR((SPItem *) items->data)) {
946                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
947                 repr->setAttribute("inkscape:flatsided", "false");
948                 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
949                 modmade = true;
950             }
951         }
952     }
953     if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
954                                   /* TODO: annotate */ "toolbox.cpp:953");
956     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
958     spinbutton_defocus(GTK_OBJECT(tbl));
961 static void
962 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
964     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
966     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
967         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
968     }
970     // quit if run by the attr_changed listener
971     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
972         return;
973     }
975     // in turn, prevent listener from responding
976     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
978     bool modmade = false;
980     Inkscape::Selection *selection = sp_desktop_selection(desktop);
981     GSList const *items = selection->itemList();
982     for (; items != NULL; items = items->next) {
983         if (SP_IS_STAR((SPItem *) items->data)) {
984             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
985             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
986             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
987             modmade = true;
988         }
989     }
990     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
991                                    /* TODO: annotate */ "toolbox.cpp:990");
993     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
995     spinbutton_defocus(GTK_OBJECT(tbl));
999 static void
1000 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1002     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1004     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1005         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1006     }
1008     // quit if run by the attr_changed listener
1009     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1010         return;
1011     }
1013     // in turn, prevent listener from responding
1014     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1016     bool modmade = false;
1018     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1019     GSList const *items = selection->itemList();
1020     for (; items != NULL; items = items->next) {
1021         if (SP_IS_STAR((SPItem *) items->data)) {
1022             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1023             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1024             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1025             modmade = true;
1026         }
1027     }
1028     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
1029                                    /* TODO: annotate */ "toolbox.cpp:1028");
1031     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1033     spinbutton_defocus(GTK_OBJECT(tbl));
1037 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1038                                        gchar const *old_value, gchar const *new_value,
1039                                        bool is_interactive, gpointer data)
1041     GtkWidget *tbl = GTK_WIDGET(data);
1043     // quit if run by the _changed callbacks
1044     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1045         return;
1046     }
1048     // in turn, prevent callbacks from responding
1049     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1051     GtkAdjustment *adj;
1053     if (!strcmp(name, "inkscape:randomized")) {
1054         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1055         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1056     } else if (!strcmp(name, "inkscape:rounded")) {
1057         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1058         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1059     } else if (!strcmp(name, "inkscape:flatsided")) {
1060         GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1061         GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1062         char const *flatsides = repr->attribute("inkscape:flatsided");
1063         if (flatsides && !strcmp(flatsides,"false" )) {
1064             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1065             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1066         } else {
1067             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1068             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1069         }
1070     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1071         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1072         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1073         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1074         if (r2 < r1) {
1075             gtk_adjustment_set_value(adj, r2/r1);
1076         } else {
1077             gtk_adjustment_set_value(adj, r1/r2);
1078         }
1079     } else if (!strcmp(name, "sodipodi:sides")) {
1080         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1081         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1082     }
1084     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1088 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1090     NULL, /* child_added */
1091     NULL, /* child_removed */
1092     star_tb_event_attr_changed,
1093     NULL, /* content_changed */
1094     NULL  /* order_changed */
1095 };
1098 /**
1099  *  \param selection Should not be NULL.
1100  */
1101 static void
1102 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1104     int n_selected = 0;
1105     Inkscape::XML::Node *repr = NULL;
1106     Inkscape::XML::Node *oldrepr = NULL;
1108     for (GSList const *items = selection->itemList();
1109          items != NULL;
1110          items = items->next)
1111     {
1112         if (SP_IS_STAR((SPItem *) items->data)) {
1113             n_selected++;
1114             repr = SP_OBJECT_REPR((SPItem *) items->data);
1115         }
1116     }
1118     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1120     if (n_selected == 0) {
1121         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1122     } else if (n_selected == 1) {
1123         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1125         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1126         if (oldrepr) { // remove old listener
1127             sp_repr_remove_listener_by_data(oldrepr, tbl);
1128             Inkscape::GC::release(oldrepr);
1129             oldrepr = 0;
1130             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1131         }
1133         if (repr) {
1134             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1135             Inkscape::GC::anchor(repr);
1136             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1137             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1138         }
1139     } else {
1140         // FIXME: implement averaging of all parameters for multiple selected stars
1141         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1142         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1143     }
1147 static void
1148 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1150     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1151     // callbacks to lump all the changes for all selected objects in one undo step
1153     GtkAdjustment *adj;
1155     // fixme: make settable in prefs!
1156     gint mag = 5;
1157     gdouble prop = 0.5;
1158     gboolean flat = FALSE;
1159     gdouble randomized = 0;
1160     gdouble rounded = 0;
1162     GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1163     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  flat);
1164     GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1165     gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1167     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1168     gtk_adjustment_set_value(adj, mag);
1169     gtk_adjustment_value_changed(adj);
1171     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1172     gtk_adjustment_set_value(adj, prop);
1173     gtk_adjustment_value_changed(adj);
1175     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1176     gtk_adjustment_set_value(adj, rounded);
1177     gtk_adjustment_value_changed(adj);
1179     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1180     gtk_adjustment_set_value(adj, randomized);
1181     gtk_adjustment_value_changed(adj);
1183     spinbutton_defocus(GTK_OBJECT(tbl));
1187 void
1188 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1190     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1191     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1192     GtkWidget *l = gtk_label_new(NULL);
1193     gtk_label_set_markup(GTK_LABEL(l), title);
1194     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1195     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1196     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1200 static GtkWidget *
1201 sp_star_toolbox_new(SPDesktop *desktop)
1203     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1205     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1206     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1208     GtkTooltips *tt = gtk_tooltips_new();
1210     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1212     gchar const *flatsidedstr = NULL;
1214     /* Flatsided checkbox */
1215     {
1216         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1217         GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1218         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1219         flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1220         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1221             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1222         else
1223             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1224         gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1225         gtk_widget_show(fscb);
1226         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1227         gtk_container_add(GTK_CONTAINER(hb), fscb);
1228         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1229         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1230     }
1232     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1234     /* Magnitude */
1235     {
1236         GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1237                                          "tools.shapes.star", "magnitude", 3,
1238                                          NULL, tbl, TRUE, "altx-star",
1239                                          3, 1024, 1, 1,
1240                                          sp_stb_magnitude_value_changed, 1, 0);
1241         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1242     }
1244     /* Spoke ratio */
1245     {
1246         GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1247                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1248                                          // Base radius is the same for the closest handle.
1249                                          _("Base radius to tip radius ratio"),
1250                                          "tools.shapes.star", "proportion", 0.5,
1251                                          NULL, tbl, FALSE, NULL,
1252                                          0.01, 1.0, 0.01, 0.1,
1253                                          sp_stb_proportion_value_changed);
1254         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1255         g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1256         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1257             gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1258         else
1259             gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1260     }
1262     /* Roundedness */
1263     {
1264         GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1265                                          "tools.shapes.star", "rounded", 0.0,
1266                                          NULL, tbl, FALSE, NULL,
1267                                          -100.0, 100.0, 0.01, 0.1,
1268                                          sp_stb_rounded_value_changed);
1269         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1270     }
1272     /* Randomization */
1273     {
1274         GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1275                                          "tools.shapes.star", "randomized", 0.0,
1276                                          NULL, tbl, FALSE, NULL,
1277                                          -10.0, 10.0, 0.001, 0.01,
1278                                          sp_stb_randomized_value_changed, 0.1, 3);
1279         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1280     }
1282     aux_toolbox_space(tbl, AUX_SPACING);
1284     /* Reset */
1285     {
1286         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1287         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1288         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1289         gtk_widget_show(b);
1290         gtk_container_add(GTK_CONTAINER(hb), b);
1291         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1292         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1293     }
1295     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1296     swatch->setWatchedTool ("tools.shapes.star", true);
1297     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1298     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1300     gtk_widget_show_all(tbl);
1301     sp_set_font_size_smaller (tbl);
1303     sigc::connection *connection = new sigc::connection(
1304         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1305         );
1306     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1308     return tbl;
1312 //########################
1313 //##       Rect         ##
1314 //########################
1316 static void 
1317 sp_rtb_sensitivize (GtkWidget *tbl)
1319     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1320     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1321     GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1323     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1324         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1325     } else {
1326         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1327     }
1331 static void
1332 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1333                           void (*setter)(SPRect *, gdouble))
1335     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1337     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1338     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1340     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1341         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1342     }
1344     // quit if run by the attr_changed listener
1345     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1346         return;
1347     }
1349     // in turn, prevent listener from responding
1350     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1352     bool modmade = false;
1353     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1354     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1355         if (SP_IS_RECT(items->data)) {
1356             if (adj->value != 0) {
1357                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1358             } else {
1359                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1360             }
1361             modmade = true;
1362         }
1363     }
1365     sp_rtb_sensitivize (tbl);
1367     if (modmade) {
1368         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT, 
1369                          /* TODO: annotate */ "toolbox.cpp:1368");
1370     }
1372     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1374     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1375     spinbutton_defocus(GTK_OBJECT(tbl));
1378 static void
1379 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1381     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1384 static void
1385 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1387     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1390 static void
1391 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1393     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1396 static void
1397 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1399     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1404 static void
1405 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1407     GtkWidget *tbl = GTK_WIDGET(obj);
1409     GtkAdjustment *adj;
1411     adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1412     gtk_adjustment_set_value(adj, 0.0);
1413     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1414     gtk_adjustment_value_changed(adj);
1416     adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1417     gtk_adjustment_set_value(adj, 0.0);
1418     gtk_adjustment_value_changed(adj);
1420     sp_rtb_sensitivize (tbl);
1422     spinbutton_defocus(GTK_OBJECT(tbl));
1425 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1426                                        gchar const *old_value, gchar const *new_value,
1427                                        bool is_interactive, gpointer data)
1429     GtkWidget *tbl = GTK_WIDGET(data);
1431     // quit if run by the _changed callbacks
1432     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1433         return;
1434     }
1436     // in turn, prevent callbacks from responding
1437     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1439     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1440     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1442     SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1443     if (SP_IS_RECT(item)) {
1444         {
1445             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1446             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1447             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1448         }
1450         {
1451             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1452             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1453             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1454         }
1456         {
1457             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1458             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1459             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1460         }
1462         {
1463             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1464             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1465             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1466         }
1467     }
1469     sp_rtb_sensitivize (tbl);
1471     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1475 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1476     NULL, /* child_added */
1477     NULL, /* child_removed */
1478     rect_tb_event_attr_changed,
1479     NULL, /* content_changed */
1480     NULL  /* order_changed */
1481 };
1483 /**
1484  *  \param selection should not be NULL.
1485  */
1486 static void
1487 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1489     int n_selected = 0;
1490     Inkscape::XML::Node *repr = NULL;
1491     SPItem *item = NULL;
1492     Inkscape::XML::Node *oldrepr = NULL;
1494     for (GSList const *items = selection->itemList();
1495          items != NULL;
1496          items = items->next) {
1497         if (SP_IS_RECT((SPItem *) items->data)) {
1498             n_selected++;
1499             item = (SPItem *) items->data;
1500             repr = SP_OBJECT_REPR(item);
1501         }
1502     }
1504     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1506     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1508     if (n_selected == 0) {
1509         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1511         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1512         gtk_widget_set_sensitive(w, FALSE);
1513         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1514         gtk_widget_set_sensitive(h, FALSE);
1516     } else if (n_selected == 1) {
1517         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1518         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1520         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1521         gtk_widget_set_sensitive(w, TRUE);
1522         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1523         gtk_widget_set_sensitive(h, TRUE);
1525         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1526         if (oldrepr) { // remove old listener
1527             sp_repr_remove_listener_by_data(oldrepr, tbl);
1528             Inkscape::GC::release(oldrepr);
1529             oldrepr = 0;
1530             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1531         }
1532         if (repr) {
1533             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1534             g_object_set_data(G_OBJECT(tbl), "item", item);
1535             Inkscape::GC::anchor(repr);
1536             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1537             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1538         }
1539     } else {
1540         // FIXME: implement averaging of all parameters for multiple selected
1541         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1542         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1543         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1544     }
1548 static GtkWidget *
1549 sp_rect_toolbox_new(SPDesktop *desktop)
1551     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1553     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1554     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1556     GtkTooltips *tt = gtk_tooltips_new();
1558     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1560     // rx/ry units menu: create
1561     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1562     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1563     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1564     // fixme: add % meaning per cent of the width/height
1566     /* W */
1567     {
1568         GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1569                                          "tools.shapes.rect", "width", 0,
1570                                          us, tbl, TRUE, "altx-rect",
1571                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1572                                          sp_rtb_width_value_changed);
1573         gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1574         gtk_widget_set_sensitive(hb, FALSE);
1575         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1576     }
1578     /* H */
1579     {
1580         GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1581                                          "tools.shapes.rect", "height", 0,
1582                                          us, tbl, FALSE, NULL,
1583                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1584                                          sp_rtb_height_value_changed);
1585         gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1586         gtk_widget_set_sensitive(hb, FALSE);
1587         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1588     }
1590     /* rx */
1591     {
1592         GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1593                                          "tools.shapes.rect", "rx", 0,
1594                                          us, tbl, FALSE, NULL,
1595                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1596                                          sp_rtb_rx_value_changed);
1597         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1598     }
1600     /* ry */
1601     {
1602         GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1603                                          "tools.shapes.rect", "ry", 0,
1604                                          us, tbl, FALSE, NULL,
1605                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1606                                          sp_rtb_ry_value_changed);
1607         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1608     }
1610     // add the units menu
1611     gtk_widget_show(us);
1612     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1613     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1615     /* Reset */
1616     {
1617         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1618         GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1619         gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1620         gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1621         gtk_widget_show(b);
1622         gtk_container_add(GTK_CONTAINER(hb), b);
1623         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1624         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1625     }
1627     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1628     swatch->setWatchedTool ("tools.shapes.rect", true);
1629     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1630     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1632     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1633     sp_rtb_sensitivize (tbl);
1635     gtk_widget_show_all(tbl);
1636     sp_set_font_size_smaller (tbl);
1638     sigc::connection *connection = new sigc::connection(
1639         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1640         );
1641     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1643     return tbl;
1646 //########################
1647 //##       Spiral       ##
1648 //########################
1650 static void
1651 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1653     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1655     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1656         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1657     }
1659     // quit if run by the attr_changed listener
1660     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1661         return;
1662     }
1664     // in turn, prevent listener from responding
1665     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1667     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1669     bool modmade = false;
1670     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1671          items != NULL;
1672          items = items->next)
1673     {
1674         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1675             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1676             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1677             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1678             modmade = true;
1679         }
1680     }
1682     g_free(namespaced_name);
1684     if (modmade) {
1685         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, 
1686                          /* TODO: annotate */ "toolbox.cpp:1685");
1687     }
1689     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1691     spinbutton_defocus(GTK_OBJECT(tbl));
1694 static void
1695 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1697     sp_spl_tb_value_changed(adj, tbl, "revolution");
1700 static void
1701 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1703     sp_spl_tb_value_changed(adj, tbl, "expansion");
1706 static void
1707 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1709     sp_spl_tb_value_changed(adj, tbl, "t0");
1712 static void
1713 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1715     GtkWidget *tbl = GTK_WIDGET(obj);
1717     GtkAdjustment *adj;
1719     // fixme: make settable
1720     gdouble rev = 5;
1721     gdouble exp = 1.0;
1722     gdouble t0 = 0.0;
1724     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1725     gtk_adjustment_set_value(adj, rev);
1726     gtk_adjustment_value_changed(adj);
1728     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1729     gtk_adjustment_set_value(adj, exp);
1730     gtk_adjustment_value_changed(adj);
1732     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1733     gtk_adjustment_set_value(adj, t0);
1734     gtk_adjustment_value_changed(adj);
1736     spinbutton_defocus(GTK_OBJECT(tbl));
1740 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1741                                          gchar const *old_value, gchar const *new_value,
1742                                          bool is_interactive, gpointer data)
1744     GtkWidget *tbl = GTK_WIDGET(data);
1746     // quit if run by the _changed callbacks
1747     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1748         return;
1749     }
1751     // in turn, prevent callbacks from responding
1752     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1754     GtkAdjustment *adj;
1755     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1756     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1758     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1759     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1761     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1762     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1764     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1768 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1769     NULL, /* child_added */
1770     NULL, /* child_removed */
1771     spiral_tb_event_attr_changed,
1772     NULL, /* content_changed */
1773     NULL  /* order_changed */
1774 };
1776 static void
1777 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1779     int n_selected = 0;
1780     Inkscape::XML::Node *repr = NULL;
1781     Inkscape::XML::Node *oldrepr = NULL;
1783     for (GSList const *items = selection->itemList();
1784          items != NULL;
1785          items = items->next)
1786     {
1787         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1788             n_selected++;
1789             repr = SP_OBJECT_REPR((SPItem *) items->data);
1790         }
1791     }
1793     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1795     if (n_selected == 0) {
1796         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1797     } else if (n_selected == 1) {
1798         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1800         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1801         if (oldrepr) { // remove old listener
1802             sp_repr_remove_listener_by_data(oldrepr, tbl);
1803             Inkscape::GC::release(oldrepr);
1804             oldrepr = 0;
1805             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1806         }
1808         if (repr) {
1809             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1810             Inkscape::GC::anchor(repr);
1811             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1812             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1813         }
1814     } else {
1815         // FIXME: implement averaging of all parameters for multiple selected
1816         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1817         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1818     }
1822 static GtkWidget *
1823 sp_spiral_toolbox_new(SPDesktop *desktop)
1825     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1826     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1827     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1829     GtkTooltips *tt = gtk_tooltips_new();
1831     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1833     /* Revolution */
1834     {
1835         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1836                                          "tools.shapes.spiral", "revolution", 3.0,
1837                                          NULL, tbl, TRUE, "altx-spiral",
1838                                          0.01, 1024.0, 0.1, 1.0,
1839                                          sp_spl_tb_revolution_value_changed, 1, 2);
1840         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1841     }
1843     /* Expansion */
1844     {
1845         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1846                                          "tools.shapes.spiral", "expansion", 1.0,
1847                                          NULL, tbl, FALSE, NULL,
1848                                          0.0, 1000.0, 0.01, 1.0,
1849                                          sp_spl_tb_expansion_value_changed);
1850         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1851     }
1853     /* T0 */
1854     {
1855         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1856                                          "tools.shapes.spiral", "t0", 0.0,
1857                                          NULL, tbl, FALSE, NULL,
1858                                          0.0, 0.999, 0.01, 1.0,
1859                                          sp_spl_tb_t0_value_changed);
1860         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1861     }
1863     aux_toolbox_space(tbl, AUX_SPACING);
1865     /* Reset */
1866     {
1867         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1868         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1869         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1870         gtk_widget_show(b);
1871         gtk_container_add(GTK_CONTAINER(hb), b);
1872         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1873         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1874     }
1876     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1877     swatch->setWatchedTool ("tools.shapes.spiral", true);
1878     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1879     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1881     gtk_widget_show_all(tbl);
1882     sp_set_font_size_smaller (tbl);
1884     sigc::connection *connection = new sigc::connection(
1885         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1886         );
1887     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1889     return tbl;
1892 //########################
1893 //##     Pen/Pencil    ##
1894 //########################
1897 static GtkWidget *
1898 sp_pen_toolbox_new(SPDesktop *desktop)
1900     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1901     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1902     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1904     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1905     swatch->setWatchedTool ("tools.freehand.pen", true);
1906     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1907     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1909     gtk_widget_show_all(tbl);
1910     sp_set_font_size_smaller (tbl);
1912     return tbl;
1915 static GtkWidget *
1916 sp_pencil_toolbox_new(SPDesktop *desktop)
1918     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1919     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1920     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1922     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1923     swatch->setWatchedTool ("tools.freehand.pencil", true);
1924     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1925     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1927     gtk_widget_show_all(tbl);
1928     sp_set_font_size_smaller (tbl);
1930     return tbl;
1934 //########################
1935 //##     Calligraphy    ##
1936 //########################
1938 static void
1939 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1941     prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1942     spinbutton_defocus(GTK_OBJECT(tbl));
1945 static void
1946 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1948     prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1949     spinbutton_defocus(GTK_OBJECT(tbl));
1952 static void
1953 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1955     prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1956     spinbutton_defocus(GTK_OBJECT(tbl));
1959 static void
1960 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1962     prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1963     spinbutton_defocus(GTK_OBJECT(tbl));
1966 static void
1967 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1969     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1970     spinbutton_defocus(GTK_OBJECT(tbl));
1973 static void
1974 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1976     prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1977     spinbutton_defocus(GTK_OBJECT(tbl));
1980 static void
1981 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1983     prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1984     spinbutton_defocus(GTK_OBJECT(tbl));
1987 static void
1988 sp_ddc_cap_rounding_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1990     prefs_set_double_attribute("tools.calligraphic", "cap_rounding", adj->value);
1991     spinbutton_defocus(GTK_OBJECT(tbl));
1994 static void
1995 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1997     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
2000 static void
2001 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
2003     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
2005     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2008 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
2010     // FIXME: make defaults settable via Inkscape Options
2011     struct KeyValue {
2012         char const *key;
2013         double value;
2014     } const key_values[] = {
2015         {"mass", 0.02},
2016         {"drag", 1.0},
2017         {"angle", 30.0},
2018         {"width", 15},
2019         {"thinning", 0.1},
2020         {"tremor", 0.0},
2021         {"flatness", 0.9},
2022         {"cap_rounding", 0.0}
2023     };
2025     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2026         KeyValue const &kv = key_values[i];
2027         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2028         gtk_adjustment_set_value(&adj, kv.value);
2029     }
2031     spinbutton_defocus(GTK_OBJECT(tbl));
2034 static GtkWidget *
2035 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2037     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2038     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2039     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2041     GtkTooltips *tt = gtk_tooltips_new();
2042     GtkWidget *calligraphy_angle;
2044     //  interval
2045     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2047     /* Width */
2048     {
2049         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2050                                          "tools.calligraphic", "width", 15,
2051                                          NULL, tbl, TRUE, "altx-calligraphy",
2052                                          1, 100, 1.0, 10.0,
2053                                          sp_ddc_width_value_changed,  0.01, 0, 100);
2054         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2055     }
2057     /* Thinning */
2058     {
2059         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)"),
2060                                          "tools.calligraphic", "thinning", 0.1,
2061                                          NULL, tbl, FALSE, NULL,
2062                                          -1.0, 1.0, 0.01, 0.1,
2063                                          sp_ddc_velthin_value_changed, 0.01, 2);
2064         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2065     }
2067     //  interval
2068     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2070     /* Angle */
2071     {
2072         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2073                                              "tools.calligraphic", "angle", 30,
2074                                              NULL, tbl, TRUE, "calligraphy-angle",
2075                                              -90.0, 90.0, 1.0, 10.0,
2076                                              sp_ddc_angle_value_changed, 1, 0);
2077         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2078     }
2080     /* Fixation */
2081     {
2082         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2083                                          "tools.calligraphic", "flatness", 0.9,
2084                                          NULL, tbl, FALSE, NULL,
2085                                          0.0, 1.0, 0.01, 0.1,
2086                                          sp_ddc_flatness_value_changed, 0.01, 2);
2087         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2088     }
2090     /* Cap Rounding */
2091     {
2092         // TRANSLATORS: "cap" means "end" (both start and finish) here
2093         GtkWidget *hb = sp_tb_spinbutton(_("Round:"), _("How much the ends of a stroke are rounded"),
2094                                          "tools.calligraphic", "cap_rounding", 0.0,
2095                                          NULL, tbl, FALSE, NULL,
2096                                          0.0, 1.0, 0.01, 0.1,
2097                                          sp_ddc_cap_rounding_value_changed, 0.01, 2);
2098         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2099     }
2101     //  interval
2102     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2104     /* Tremor */
2105     {
2106         GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2107                                          "tools.calligraphic", "tremor", 0.0,
2108                                          NULL, tbl, FALSE, NULL,
2109                                          0.0, 1.0, 0.01, 0.1,
2110                                          sp_ddc_tremor_value_changed, 0.01, 2);
2111         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2112     }
2114     /* Mass */
2115     {
2116         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2117                                          "tools.calligraphic", "mass", 0.02,
2118                                          NULL, tbl, FALSE, NULL,
2119                                          0.0, 1.0, 0.01, 0.1,
2120                                          sp_ddc_mass_value_changed, 0.01, 2);
2121         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2122     }
2124     /* Drag */
2125     {
2126         // TRANSLATORS: "drag" means "resistance" here
2127         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2128                                          "tools.calligraphic", "drag", 1,
2129                                          NULL, tbl, FALSE, NULL,
2130                                          0.0, 1.0, 0.01, 0.1,
2131                                          sp_ddc_drag_value_changed, 0.01, 2);
2132         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2133     }
2135     //  interval
2136     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2138     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2139     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2141     /* Use Pressure button */
2142     {
2143     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2144                                                  SP_BUTTON_TYPE_TOGGLE,
2145                                                  NULL,
2146                                                  "use_pressure",
2147                                                  _("Use the pressure of the input device to alter the width of the pen"),
2148                                                  tt);
2149     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2150     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2151     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2152     }
2154     /* Use Tilt button */
2155     {
2156     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2157                                                  SP_BUTTON_TYPE_TOGGLE,
2158                                                  NULL,
2159                                                  "use_tilt",
2160                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2161                                                  tt);
2162     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2163     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2164     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2165     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2166     }
2168     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2169     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2171     /* Reset */
2172     {
2173         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2174         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2175         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2176         gtk_widget_show(b);
2177         gtk_container_add(GTK_CONTAINER(hb), b);
2178         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2179         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2180     }
2183     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2184     swatch->setWatchedTool ("tools.calligraphic", true);
2185     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2186     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2188     gtk_widget_show_all(tbl);
2189     sp_set_font_size_smaller (tbl);
2191     return tbl;
2195 //########################
2196 //##    Circle / Arc    ##
2197 //########################
2199 static void 
2200 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2202     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2203     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2205     if (v1 == 0 && v2 == 0) {
2206         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2207             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2208             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2209         }
2210     } else {
2211         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2212         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2213     }
2216 static void
2217 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2219     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2221     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2222         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2223     }
2225     // quit if run by the attr_changed listener
2226     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2227         return;
2228     }
2230     // in turn, prevent listener from responding
2231     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2233     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2235     bool modmade = false;
2236     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2237          items != NULL;
2238          items = items->next)
2239     {
2240         SPItem *item = SP_ITEM(items->data);
2242         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2244             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2245             SPArc *arc = SP_ARC(item);
2247             if (!strcmp(value_name, "start"))
2248                 ge->start = (adj->value * M_PI)/ 180;
2249             else
2250                 ge->end = (adj->value * M_PI)/ 180;
2252             sp_genericellipse_normalize(ge);
2253             ((SPObject *)arc)->updateRepr();
2254             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2256             modmade = true;
2257         }
2258     }
2260     g_free(namespaced_name);
2262     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2264     sp_arctb_sensitivize (tbl, adj->value, other->value);
2266     if (modmade) {
2267         sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC, 
2268                                /* TODO: annotate */ "toolbox.cpp:2247");
2269     }
2271     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2272     spinbutton_defocus(GTK_OBJECT(tbl));
2274     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2278 static void
2279 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2281     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2284 static void
2285 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2287     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2290 static void
2291 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2293     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2295     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2296         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2297             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2298         } else {
2299             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2300         }
2301     }
2303     // quit if run by the attr_changed listener
2304     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2305         return;
2306     }
2308     // in turn, prevent listener from responding
2309     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2311     bool modmade = false;
2313     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2314         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2315              items != NULL;
2316              items = items->next)
2317         {
2318             if (SP_IS_ARC((SPItem *) items->data)) {
2319                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2320                 repr->setAttribute("sodipodi:open", "true");
2321                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2322                 modmade = true;
2323             }
2324         }
2325     } else {
2326         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2327              items != NULL;
2328              items = items->next)
2329         {
2330             if (SP_IS_ARC((SPItem *) items->data))    {
2331                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2332                 repr->setAttribute("sodipodi:open", NULL);
2333                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2334                 modmade = true;
2335             }
2336         }
2337     }
2339     if (modmade) {
2340         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, 
2341                          /* TODO: annotate */ "toolbox.cpp:2320");
2342     }
2344     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2346     spinbutton_defocus(GTK_OBJECT(tbl));
2349 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2351     GtkWidget *tbl = GTK_WIDGET(obj);
2353     GtkAdjustment *adj;
2354     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2355     gtk_adjustment_set_value(adj, 0.0);
2356     gtk_adjustment_value_changed(adj);
2358     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2359     gtk_adjustment_set_value(adj, 0.0);
2360     gtk_adjustment_value_changed(adj);
2362     spinbutton_defocus(GTK_OBJECT(tbl));
2365 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2366                                       gchar const *old_value, gchar const *new_value,
2367                                       bool is_interactive, gpointer data)
2369     GtkWidget *tbl = GTK_WIDGET(data);
2371     // quit if run by the _changed callbacks
2372     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2373         return;
2374     }
2376     // in turn, prevent callbacks from responding
2377     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2379     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2380     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2382     GtkAdjustment *adj1,*adj2;
2383     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2384     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2385     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2386     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2388     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2390     char const *openstr = NULL;
2391     openstr = repr->attribute("sodipodi:open");
2392     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2394     if (openstr) {
2395         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2396     } else {
2397         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2398     }
2400     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2403 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2404     NULL, /* child_added */
2405     NULL, /* child_removed */
2406     arc_tb_event_attr_changed,
2407     NULL, /* content_changed */
2408     NULL  /* order_changed */
2409 };
2412 static void
2413 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2415     int n_selected = 0;
2416     Inkscape::XML::Node *repr = NULL;
2417     Inkscape::XML::Node *oldrepr = NULL;
2419     for (GSList const *items = selection->itemList();
2420          items != NULL;
2421          items = items->next)
2422     {
2423         if (SP_IS_ARC((SPItem *) items->data)) {
2424             n_selected++;
2425             repr = SP_OBJECT_REPR((SPItem *) items->data);
2426         }
2427     }
2429     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2431     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2432     if (n_selected == 0) {
2433         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2434     } else if (n_selected == 1) {
2435         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2436         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2438         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2440         if (oldrepr) { // remove old listener
2441             sp_repr_remove_listener_by_data(oldrepr, tbl);
2442             Inkscape::GC::release(oldrepr);
2443             oldrepr = 0;
2444             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2445         }
2447         if (repr) {
2448             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2449             Inkscape::GC::anchor(repr);
2450             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2451             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2452         }
2453     } else {
2454         // FIXME: implement averaging of all parameters for multiple selected
2455         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2456         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2457         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2458     }
2462 static GtkWidget *
2463 sp_arc_toolbox_new(SPDesktop *desktop)
2465     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2467     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2468     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2470     GtkTooltips *tt = gtk_tooltips_new();
2472     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2474     /* Start */
2475     {
2476         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2477                                          "tools.shapes.arc", "start", 0.0,
2478                                          NULL, tbl, TRUE, "altx-arc",
2479                                          -360.0, 360.0, 1.0, 10.0,
2480                                          sp_arctb_start_value_changed);
2481         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2482     }
2484     /* End */
2485     {
2486         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2487                                          "tools.shapes.arc", "end", 0.0,
2488                                          NULL, tbl, FALSE, NULL,
2489                                          -360.0, 360.0, 1.0, 10.0,
2490                                          sp_arctb_end_value_changed);
2491         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2492     }
2494     /* Segments / Pie checkbox */
2495     {
2496         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2497         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2498         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2500         gchar const *openstr = NULL;
2501         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2502         if (!openstr || (openstr && !strcmp(openstr, "false")))
2503             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2504         else
2505             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2507         gtk_widget_show(fscb);
2508         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2509         gtk_container_add(GTK_CONTAINER(hb), fscb);
2510         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2511         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2512     }
2514     /* Make Whole */
2515     {
2516         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2517         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2518         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2519         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2520         gtk_widget_show(b);
2521         gtk_container_add(GTK_CONTAINER(hb), b);
2522         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2523         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2524     }
2526     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2527     // sensitivize make whole and open checkbox
2528     {
2529         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2530         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2531         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2532     }
2534     sigc::connection *connection = new sigc::connection(
2535         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2536         );
2537     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2539     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2540     swatch->setWatchedTool ("tools.shapes.arc", true);
2541     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2542     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2544     gtk_widget_show_all(tbl);
2545     sp_set_font_size_smaller (tbl);
2547     return tbl;
2553 // toggle button callbacks and updaters
2555 //########################
2556 //##      Dropper       ##
2557 //########################
2559 static void toggle_dropper_pick_alpha (GtkWidget *button, gpointer tbl) {
2560     prefs_set_int_attribute ("tools.dropper", "pick", 
2561         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
2562     GtkWidget *set_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "set_checkbox");
2563     if (set_checkbox) {
2564         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
2565             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), TRUE);
2566         } else {
2567             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), FALSE);
2568         }
2569     }
2572 static void toggle_dropper_set_alpha (GtkWidget *button, gpointer data) {
2573     prefs_set_int_attribute ("tools.dropper", "setalpha", 
2574         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
2578 /**
2579  * Copy the current saved desktop color to the clipboard as full hex + alpha
2580  * color representation. This is useful for passing values between various 
2581  * input boxes, or directly to xml.
2582  */
2583 /* static void
2584 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2586     GtkWidget *tbl = GTK_WIDGET(obj);
2587     
2588     SPDesktop *desktop = 
2589         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2591    
2592     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2593 }*/
2596 /**
2597  * Copies currently saved desktop color to the clipboard as a hex value. This 
2598  * is useful for editing webpages and needing a value quickly for web
2599  * colors.
2600  * 
2601  * TODO: When the toggle of the dropper is set to not mix color against 
2602  *       page background, this still just gets the color of the page and 
2603  *       doesn't get the actual mixed against background which is needed 
2604  *       for the hex value ppl. want for web pages, etc.
2605  */
2607 /* static void
2608 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2610     GtkWidget *tbl = GTK_WIDGET(obj);
2611     
2612     SPDesktop *desktop = 
2613         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2614     
2615     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2616 }*/
2619 /**
2620  * Sets the input boxes with the changed color and opacity. This is used as a 
2621  * callback for style changing.
2622  */
2623 /* static bool
2624 sp_style_changed (const SPCSSAttr *css, gpointer data)
2626     // GrDrag *drag = (GrDrag *) data;
2627     
2628     // set fill of text entry box
2629     if (css->attribute("fill"))
2630         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2631             css->attribute("fill")); 
2633     // set opacity of text entry box
2634     if (css->attribute("fill-opacity"))
2635         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2636             css->attribute("fill-opacity")); 
2637     
2638     // set fill of text entry box
2639     if (css->attribute("stroke"))
2640         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2641             css->attribute("stroke")); 
2643     // set opacity of text entry box
2644     if (css->attribute("stroke-opacity"))
2645         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2646             css->attribute("stroke-opacity"));
2647     return false;
2650 */
2653 /**
2654  * Dropper auxiliary toolbar construction and setup.
2655  *
2656  * TODO: Would like to add swatch of current color.
2657  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2658  *       can drag and drop places. Will provide a nice mixing palette.
2659  */
2660 static GtkWidget *
2661 sp_dropper_toolbox_new(SPDesktop *desktop)
2663     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2665     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2666     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2668     GtkTooltips *tt = gtk_tooltips_new();
2670     
2671     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2672                        AUX_BETWEEN_BUTTON_GROUPS);
2673     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2676     
2677     /* RGB Input Field */
2678  /*   {
2679         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2680         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2681         gtk_widget_show (dropper_rgba_label);
2682         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2683         
2684         dropper_rgb_entry = gtk_entry_new ();
2685         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2686         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2687         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2688         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2689                          _("Hexidecimal representation of last selected "
2690                            "color"), 
2691                          NULL);
2692         gtk_widget_show (dropper_rgb_entry);
2693         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2694         
2695         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2696                            AUX_BETWEEN_BUTTON_GROUPS);
2697     } */
2698     
2699     /* Opacity Input Field */
2700 /*    {
2701         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2702         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2703         gtk_widget_show (dropper_opacity_label);
2704         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2705         
2706         dropper_opacity_entry = gtk_entry_new ();
2707         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2708         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2709         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2710         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2711                          _("Opacity of last selected color"), 
2712                          NULL);
2713         gtk_widget_show (dropper_opacity_entry);
2714         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2715         
2716         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2717                            AUX_BETWEEN_BUTTON_GROUPS);
2718     } */
2719     
2720     
2721     /* Copy to Clipboard */
2722 /*    {
2723         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2724         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2725         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2726                                       "RGB + Alpha (RGBA) to "
2727                                       "clipboard"), 
2728                              NULL);
2729         gtk_widget_show(b);
2730         gtk_container_add(GTK_CONTAINER(hb), b);
2731         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2732             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2733         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2734                            AUX_BETWEEN_BUTTON_GROUPS);
2735     } */
2738     /* Copy to Clipboard as HEX */
2739 /*    {
2740         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2741         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2742         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2743                                       "hexidecimal RGB without alpha " 
2744                                       "to clipboard"), NULL);
2745         gtk_widget_show(b);
2746         gtk_container_add(GTK_CONTAINER(hb), b);
2747         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2748             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2749         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2750                            AUX_BETWEEN_BUTTON_GROUPS);
2751     } */
2752     
2753     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2754     
2755     {
2756         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2758         GtkWidget *button = gtk_check_button_new_with_label(_("Pick alpha"));
2759         gtk_tooltips_set_tip(tt, button, _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"), NULL);
2760         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2761                                       prefs_get_int_attribute ("tools.dropper", 
2762                                                                "pick", 1));
2763         gtk_widget_show(button);
2764         gtk_container_add (GTK_CONTAINER (hb), button);
2765         gtk_object_set_data(GTK_OBJECT(tbl), "pick_checkbox", button);
2766         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_pick_alpha), tbl);
2767         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2768                    AUX_BETWEEN_BUTTON_GROUPS);
2769     }
2771     {
2772         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2774         GtkWidget *button = gtk_check_button_new_with_label(_("Set alpha"));
2775         gtk_tooltips_set_tip(tt, button, _("If alpha was picked, assign it to selection as fill or stroke transparency"), NULL);
2776         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2777                                       prefs_get_int_attribute ("tools.dropper", 
2778                                                                "setalpha", 1));
2779         gtk_widget_show(button);
2780         gtk_container_add (GTK_CONTAINER (hb), button);
2781         gtk_object_set_data(GTK_OBJECT(tbl), "set_checkbox", button);
2782         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_set_alpha), tbl);
2784         // make sure it's disabled if we're not picking alpha
2785         GtkWidget *pick_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "pick_checkbox");
2786         if (pick_checkbox) {
2787             if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pick_checkbox))) {
2788                 gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
2789             } else {
2790                 gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
2791             }
2792         }
2794         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2795                    AUX_BETWEEN_BUTTON_GROUPS);
2796     }
2797    
2798     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2799     
2801     // where new gtkmm stuff should go
2802     
2803     gtk_widget_show_all(tbl);
2804     sp_set_font_size_smaller (tbl);
2806     /*
2807     sigc::connection *connection = new sigc::connection(
2808         desktop->connectSetStyle(
2809             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2810                        desktop)) ); 
2811     
2812     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2813                      connection); */
2814     
2815     return tbl;
2819 //########################
2820 //##    Text Toolbox    ##
2821 //########################
2822 /*
2823 static void
2824 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2826     //Call back for letter sizing spinbutton
2829 static void
2830 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2832     //Call back for line height spinbutton
2835 static void
2836 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2838     //Call back for horizontal kerning spinbutton
2841 static void
2842 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2844     //Call back for vertical kerning spinbutton
2847 static void
2848 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2850     //Call back for letter rotation spinbutton
2851 }*/
2853 namespace {
2855 bool visible = false;
2857 void
2858 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2861     SPStyle *query =
2862         sp_style_new ();
2864     int result_family =
2865         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); 
2867     int result_style =
2868         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); 
2870     int result_numbers =
2871         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2873     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2875     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2876     if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2877     {
2878         Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
2880         if (repr)
2881         {
2882             sp_style_read_from_repr (query, repr);
2883         }
2884         else
2885         {
2886             return;
2887         }
2888     }
2890     if (query->text)
2891     {
2892         if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
2893             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
2894             gtk_entry_set_text (GTK_ENTRY (entry), "");
2896         } else if (query->text->font_family.value) {
2898             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
2899             gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
2901             Gtk::TreePath path;
2902             try {
2903                 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2904             } catch (...) {
2905                 return;
2906             }
2908             GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
2909             GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
2911             g_object_set_data (G_OBJECT (tselection), "block", gpointer(1)); 
2913             gtk_tree_selection_select_path (tselection, path.gobj());
2914             gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
2916             g_object_set_data (G_OBJECT (tselection), "block", gpointer(0)); 
2917         }
2919         //Size
2920         GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
2921         char *str = g_strdup_printf ("%.5g", query->font_size.computed);
2922         g_object_set_data (tbl, "size-block", gpointer(1)); 
2923         gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
2924         g_object_set_data (tbl, "size-block", gpointer(0)); 
2925         free (str);
2927         //Anchor
2928         if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
2929         {
2930             GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
2931             g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2932             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2933             g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2934         }
2935         else
2936         {
2937             if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
2938             {
2939                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
2940                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2941                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2942                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2943             }
2944             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
2945             {
2946                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
2947                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2948                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2949                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2950             }
2951             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
2952             {
2953                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
2954                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2955                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2956                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2957             }
2958         }
2960         //Style
2961         {
2962             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
2964             gboolean active = gtk_toggle_button_get_active (button);
2965             gboolean check  = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700); 
2967             if (active != check) 
2968             {
2969                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2970                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2971                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2972             }
2973         }
2975         {
2976             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
2978             gboolean active = gtk_toggle_button_get_active (button);
2979             gboolean check  = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL); 
2981             if (active != check)
2982             {
2983                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2984                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2985                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2986             }
2987         }
2989         //Orientation
2990         //locking both buttons, changing one affect all group (both)
2991         GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
2992         g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2993         
2994         GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
2995         g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
2996         
2997         if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
2998         {
2999             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3000         }
3001         else
3002         {
3003             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3004         }
3005         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3006         g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3007     }
3010 void
3011 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl) 
3013     sp_text_toolbox_selection_changed (selection, tbl); 
3016 void
3017 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3019     sp_text_toolbox_selection_changed (NULL, tbl); 
3022 void
3023 sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
3024                                 GObject             *tbl) 
3026     SPDesktop    *desktop = SP_ACTIVE_DESKTOP;
3027     GtkTreeModel *model = 0;
3028     GtkWidget    *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3029     GtkWidget    *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3030     GtkTreeIter   iter;
3031     char         *family = 0;
3033     gdk_pointer_ungrab (GDK_CURRENT_TIME);
3034     gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3036     if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3037         return;
3038     }
3040     gtk_tree_model_get (model, &iter, 0, &family, -1);
3042     if (g_object_get_data (G_OBJECT (selection), "block"))
3043     {
3044         gtk_entry_set_text (GTK_ENTRY (entry), family);
3045         return;
3046     }
3047         
3048     gtk_widget_hide (popdown);
3049     visible = false;
3051     gtk_entry_set_text (GTK_ENTRY (entry), family);
3053     SPStyle *query =
3054         sp_style_new ();
3056     int result_numbers =
3057         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3059     SPCSSAttr *css = sp_repr_css_attr_new (); 
3060     sp_repr_css_set_property (css, "font-family", family); 
3062     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3063     if (result_numbers == QUERY_STYLE_NOTHING)
3064     {
3065         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3066         sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3067     }
3068     else
3069     {
3070         sp_desktop_set_style (desktop, css, true, true);
3071     }
3073     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3074                       /* TODO: annotate */ "toolbox.cpp:3024");
3075     sp_repr_css_attr_unref (css);
3076     free (family);
3077     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
3079     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3082 void
3083 sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
3084                                        GObject      *tbl) 
3086     const char *family = gtk_entry_get_text (entry);
3088     try {    
3089         Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3090         GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3091         GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3092         gtk_tree_selection_select_path (selection, path.gobj());
3093         gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3094         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
3095     } catch (...) {
3096         if (family && strlen (family))
3097         {
3098             gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3099         }
3100     }
3103 void
3104 sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
3105                                    gpointer          data)
3107     if (g_object_get_data (G_OBJECT (button), "block")) return;
3108     if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3109     int prop = GPOINTER_TO_INT(data); 
3111     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3112     SPCSSAttr *css = sp_repr_css_attr_new (); 
3114     switch (prop)
3115     {
3116         case 0:
3117         {
3118             sp_repr_css_set_property (css, "text-anchor", "start"); 
3119             sp_repr_css_set_property (css, "text-align", "start"); 
3120             break;
3121         }
3122         case 1:
3123         {
3124             sp_repr_css_set_property (css, "text-anchor", "middle"); 
3125             sp_repr_css_set_property (css, "text-align", "center"); 
3126             break;
3127         }
3129         case 2:
3130         {
3131             sp_repr_css_set_property (css, "text-anchor", "end"); 
3132             sp_repr_css_set_property (css, "text-align", "end"); 
3133             break;
3134         }
3136         case 3:
3137         {
3138             sp_repr_css_set_property (css, "text-anchor", "start"); 
3139             sp_repr_css_set_property (css, "text-align", "justify"); 
3140             break;
3141         }
3142     }
3144     SPStyle *query =
3145         sp_style_new ();
3146     int result_numbers =
3147         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3149     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3150     if (result_numbers == QUERY_STYLE_NOTHING)
3151     {
3152         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3153     }
3155     sp_desktop_set_style (desktop, css, true, true);
3156     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3157                       /* TODO: annotate */ "toolbox.cpp:3107");
3158     sp_repr_css_attr_unref (css);
3160     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3163 void
3164 sp_text_toolbox_style_toggled (GtkToggleButton  *button,
3165                                gpointer          data)
3167     if (g_object_get_data (G_OBJECT (button), "block")) return;
3169     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3170     SPCSSAttr   *css        = sp_repr_css_attr_new (); 
3171     int          prop       = GPOINTER_TO_INT(data); 
3172     bool         active     = gtk_toggle_button_get_active (button);
3175     switch (prop)
3176     {
3177         case 0:
3178         {
3179             sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" ); 
3180             break;
3181         }
3183         case 1:
3184         {
3185             sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal"); 
3186             break;
3187         }
3188     }
3190     SPStyle *query =
3191         sp_style_new ();
3192     int result_numbers =
3193         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3195     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3196     if (result_numbers == QUERY_STYLE_NOTHING)
3197     {
3198         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3199     }
3201     sp_desktop_set_style (desktop, css, true, true);
3202     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3203                       /* TODO: annotate */ "toolbox.cpp:3153");
3204     sp_repr_css_attr_unref (css);
3206     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3209 void
3210 sp_text_toolbox_orientation_toggled (GtkRadioButton  *button,
3211                                      gpointer         data)
3213     if (g_object_get_data (G_OBJECT (button), "block")) {
3214         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3215         return;
3216     }
3217     
3218     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3219     SPCSSAttr   *css        = sp_repr_css_attr_new (); 
3220     int          prop       = GPOINTER_TO_INT(data); 
3222     switch (prop)
3223     {
3224         case 0:
3225         {
3226             sp_repr_css_set_property (css, "writing-mode", "lr");
3227             break;
3228         }
3230         case 1:
3231         {
3232             sp_repr_css_set_property (css, "writing-mode", "tb"); 
3233             break;
3234         }
3235     }
3237     SPStyle *query =
3238         sp_style_new ();
3239     int result_numbers =
3240         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3242     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3243     if (result_numbers == QUERY_STYLE_NOTHING)
3244     {
3245         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3246     }
3248     sp_desktop_set_style (desktop, css, true, true);
3249     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3250                       /* TODO: annotate */ "toolbox.cpp:3200");
3251     sp_repr_css_attr_unref (css);
3253     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3256 gboolean
3257 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3259     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3260     if (!desktop) return FALSE;
3262     switch (get_group0_keyval (event)) {
3263         case GDK_Escape: // defocus
3264             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3265             return TRUE; // I consumed the event
3266             break;
3267         case GDK_Return: // defocus
3268         case GDK_KP_Enter:
3269             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3270             return TRUE; // I consumed the event
3271             break;
3272     }
3273     return FALSE;
3276 gboolean
3277 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3279     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3280     if (!desktop) return FALSE;
3282     switch (get_group0_keyval (event)) {
3283         case GDK_Escape: // defocus
3284             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3285             sp_text_toolbox_selection_changed (NULL, tbl); // update
3286             return TRUE; // I consumed the event
3287             break;
3288     }
3289     return FALSE;
3292 gboolean
3293 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3295     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3296     if (!desktop) return FALSE;
3298     switch (get_group0_keyval (event)) {
3299         case GDK_Escape: // defocus
3300             gtk_widget_hide (w);
3301             visible = false;
3302             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3303             return TRUE; // I consumed the event
3304             break;
3305     }
3306     return FALSE;
3310 void
3311 sp_text_toolbox_size_changed  (GtkComboBox *cbox,
3312                                GObject     *tbl) 
3314     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3316     if (g_object_get_data (tbl, "size-block")) return;
3318 #if GTK_CHECK_VERSION(2,6,0)
3319     char *text = gtk_combo_box_get_active_text (cbox);
3320 #else // GTK_CHECK_VERSION(2,6,0)
3321     GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3322     GtkTreeIter iter;
3323     char *text = NULL;
3325     if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3326         gtk_tree_model_get (model, &iter, 0, &text, -1);
3327 #endif // GTK_CHECK_VERSION(2,6,0)
3329     SPCSSAttr *css = sp_repr_css_attr_new (); 
3330     sp_repr_css_set_property (css, "font-size", text); 
3331     free (text);
3333     SPStyle *query =
3334         sp_style_new ();
3335     int result_numbers =
3336         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3338     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3339     if (result_numbers == QUERY_STYLE_NOTHING)
3340     {
3341         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3342     }
3344     sp_desktop_set_style (desktop, css, true, true);
3345     sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE, 
3346                             /* TODO: annotate */ "toolbox.cpp:3296");
3347     sp_repr_css_attr_unref (css);
3350     if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3351         gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3354 void
3355 sp_text_toolbox_text_popdown_clicked    (GtkButton          *button,
3356                                          GObject            *tbl)
3358     GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3359     GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3360     int x, y;
3362     if (!visible)
3363     {
3364         gdk_window_get_origin (widget->window, &x, &y);
3365         gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space 
3366         gtk_widget_show_all (popdown);
3368         gdk_pointer_grab (widget->window, TRUE,
3369                           GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3370                                         GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3371                                         GDK_POINTER_MOTION_MASK),
3372                           NULL, NULL, GDK_CURRENT_TIME);
3374         gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3376         visible = true;
3377     }
3378     else
3379     {
3380         gdk_pointer_ungrab (GDK_CURRENT_TIME);
3381         gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3382         gtk_widget_hide (popdown);
3383         visible = false;
3384     }
3387 gboolean
3388 sp_text_toolbox_entry_focus_in  (GtkWidget        *entry,
3389                                  GdkEventFocus    *event,
3390                                  GObject          *tbl)
3392     gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3393     return FALSE;
3396 gboolean
3397 sp_text_toolbox_popdown_focus_out (GtkWidget        *popdown,
3398                                    GdkEventFocus    *event,
3399                                    GObject          *tbl)
3401     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3403     gtk_widget_hide (popdown);
3404     visible = false;
3405     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3406     return TRUE;
3409 void
3410 cell_data_func  (GtkTreeViewColumn *column,
3411                  GtkCellRenderer   *cell,
3412                  GtkTreeModel      *tree_model,
3413                  GtkTreeIter       *iter,
3414                  gpointer           data)
3416     char        *family,
3417         *family_escaped,
3418         *sample_escaped;
3420     static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3422     gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3424     family_escaped = g_markup_escape_text (family, -1);
3425     sample_escaped = g_markup_escape_text (sample, -1);
3426     
3427     std::stringstream markup; 
3428     markup << family_escaped << "  <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3429     g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3431     free (family);
3432     free (family_escaped);
3433     free (sample_escaped);
3436 static void delete_completion(GObject *obj, GtkWidget *entry) {
3437     GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3438     if (completion) {
3439         gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3440         g_object_unref (completion);
3441     }
3444 GtkWidget*
3445 sp_text_toolbox_new (SPDesktop *desktop)
3447     GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
3449     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3450     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3452     GtkTooltips *tt = gtk_tooltips_new();
3453     Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3455     ////////////Family
3456     //Window
3457     GtkWidget   *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3458     gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3460     //Entry
3461     GtkWidget           *entry = gtk_entry_new ();
3462     gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3463     GtkEntryCompletion  *completion = gtk_entry_completion_new ();
3464     gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3465     gtk_entry_completion_set_text_column (completion, 0);
3466     gtk_entry_completion_set_minimum_key_length (completion, 1); 
3467     g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3468     gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3469     gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
3470     aux_toolbox_space (tbl, 1);
3471     gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3472     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
3473         
3474     //Button
3475     GtkWidget   *button = gtk_button_new ();
3476     gtk_container_add       (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3477     gtk_box_pack_start      (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3479     //Popdown
3480     GtkWidget           *sw = gtk_scrolled_window_new (NULL, NULL);
3481     GtkWidget           *treeview = gtk_tree_view_new ();
3483     GtkCellRenderer     *cell = gtk_cell_renderer_text_new ();
3484     GtkTreeViewColumn   *column = gtk_tree_view_column_new ();
3485     gtk_tree_view_column_pack_start (column, cell, FALSE);
3486     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3487     gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3488     gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3490     gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3491     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3492 #if GTK_CHECK_VERSION(2,6,0)
3493     gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3494 #endif // GTK_CHECK_VERSION(2,6,0)
3496     //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3498     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); 
3499     gtk_container_add (GTK_CONTAINER (sw), treeview);
3501     gtk_container_add (GTK_CONTAINER (window), sw);
3502     gtk_widget_set_size_request (window, 300, 450);
3504     g_signal_connect (G_OBJECT (entry),  "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3505     g_signal_connect (G_OBJECT (entry),  "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3506     g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3508     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3510     g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3511     g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3513     GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3514     g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3516     g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3517     g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3518     g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3519     g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3520     g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3522     GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3523     aux_toolbox_space (tbl, 1);
3524     GtkWidget *box = gtk_event_box_new ();
3525     gtk_container_add (GTK_CONTAINER (box), image);
3526     gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3527     g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3528     GtkTooltips *tooltips = gtk_tooltips_new ();
3529     gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3530     gtk_widget_hide (GTK_WIDGET (box));
3531     g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3533     ////////////Size
3534     const char *sizes[] = {
3535         "4", "6", "8", "9", "10", "11", "12", "13", "14",
3536         "16", "18", "20", "22", "24", "28",
3537         "32", "36", "40", "48", "56", "64", "72", "144"
3538     };
3540     GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3541     for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3542     gtk_widget_set_size_request (cbox, 80, -1);
3543     aux_toolbox_space (tbl, 1);
3544     gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3545     g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3546     g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3547     gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3549     //spacer
3550     aux_toolbox_space (tbl, 4);
3551     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3553     ////////////Text anchor
3554     GtkWidget *group   = gtk_radio_button_new (NULL);
3555     GtkWidget *row     = gtk_hbox_new (FALSE, 4);
3556     g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3558     // left
3559     GtkWidget *rbutton = group;
3560     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3561     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3562     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3564     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3565     g_object_set_data   (G_OBJECT (tbl), "text-start", rbutton);
3566     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3567     gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3569     // center
3570     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3571     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3572     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3573     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3575     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3576     g_object_set_data   (G_OBJECT (tbl), "text-middle", rbutton);
3577     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1)); 
3578     gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3580     // right
3581     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3582     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3583     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3584     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3586     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3587     g_object_set_data   (G_OBJECT (tbl), "text-end", rbutton);
3588     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3589     gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3591     // fill
3592     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3593     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3594     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3595     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3597     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3598     g_object_set_data   (G_OBJECT (tbl), "text-fill", rbutton);
3599     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3600     gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3602     aux_toolbox_space (tbl, 1);
3603     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3605     //spacer
3606     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3608     ////////////Text style
3609     row = gtk_hbox_new (FALSE, 4);
3611     // bold 
3612     rbutton = gtk_toggle_button_new (); 
3613     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3614     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3615     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3616     gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3618     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3619     g_object_set_data   (G_OBJECT (tbl), "style-bold", rbutton);
3620     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3622     // italic
3623     rbutton = gtk_toggle_button_new (); 
3624     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3625     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3626     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3627     gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3629     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3630     g_object_set_data   (G_OBJECT (tbl), "style-italic", rbutton);
3631     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1)); 
3633     aux_toolbox_space (tbl, 1);
3634     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3636     //spacer
3637     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3639     ////////////Text orientation
3640     group   = gtk_radio_button_new (NULL);
3641     row     = gtk_hbox_new (FALSE, 4);
3642     g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3644     // horizontal
3645     rbutton = group;
3646     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3647     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR)); 
3648     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3649     gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3651     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3652     g_object_set_data   (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3653     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3655     // vertical
3656     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3657     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3658     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB)); 
3659     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3660     gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3662     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3663     g_object_set_data   (G_OBJECT (tbl), "orientation-vertical", rbutton);
3664     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1)); 
3665     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3668     //watch selection
3669     Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3671     sigc::connection *c_selection_changed =
3672         new sigc::connection (sp_desktop_selection (desktop)->connectChanged 
3673                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3674     pool->add_connection ("selection-changed", c_selection_changed);
3676     sigc::connection *c_selection_modified =
3677         new sigc::connection (sp_desktop_selection (desktop)->connectModified 
3678                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3679     pool->add_connection ("selection-modified", c_selection_modified);
3681     sigc::connection *c_subselection_changed =
3682         new sigc::connection (desktop->connectToolSubselectionChanged
3683                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3684     pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3686     Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3689 #if 0
3690     // horizontal
3691     {
3692         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3693         GtkWidget *b = group = gtk_radio_button_new (NULL);
3694         gtk_container_add (GTK_CONTAINER (b), px);
3695         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3696         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3697         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3698         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3699     }
3701     // vertical
3702     {
3703         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3704         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3705         gtk_container_add (GTK_CONTAINER (b), px);
3706         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3707         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3708         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3709         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3710     }
3712     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3714     // letter spacing
3715     {
3716         {
3717             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3718             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3719             gtk_container_add (GTK_CONTAINER (hb), image);
3720             gtk_widget_show(image);
3721             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3722         }
3723     
3724         {
3725             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3726                                              "tools.text", "letter_spacing", 0.0,
3727                                              us, tbl, FALSE, NULL,
3728                                              -1000.0, 1000.0, 0.1, 0.1,
3729                                              sp_text_letter_changed, 0.1, 1);
3730             gtk_widget_set_size_request (hb, 45, 6);
3731             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3732         }
3733     }
3735     // line spacing
3736     {
3737         {
3738             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3739             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3740             gtk_container_add (GTK_CONTAINER (hb), image);
3741             gtk_widget_show(image);
3742             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3743         }
3744     
3745         {
3746             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3747                                              "tools.text", "line_spacing", 0,
3748                                              us, tbl, FALSE, NULL,
3749                                              -1000.0, 1000.0, 0.1, 0.1,
3750                                              sp_text_line_changed, 0.1, 1);
3751             gtk_widget_set_size_request (hb, 45, 0);
3752             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3753         }
3754     }
3756     {
3757         // horizontal kerning/vertical kerning units menu: create
3758         GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3759         sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3760         sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3762         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3764         // horizontal kerning
3765         {
3766             {
3767                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3768                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3769                 gtk_container_add (GTK_CONTAINER (hb), image);
3770                 gtk_widget_show(image);
3771                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3772             }
3774             {
3775                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3776                                                  "tools.text", "horizontal_kerning", 0,
3777                                                  us, tbl, FALSE, NULL,
3778                                                  -100.00, 100.00, 0.01, 0.1,
3779                                                  sp_text_horiz_kern_changed);
3780                 gtk_widget_set_size_request (hb, 45, 0);
3781                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3782             }
3783         }
3785         // vertical kerning
3786         {
3787             {
3788                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3789                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3790                 gtk_container_add (GTK_CONTAINER (hb), image);
3791                 gtk_widget_show(image);
3792                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3793             }
3794     
3795             {
3796                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3797                                                  "tools.text", "vertical_kerning", 0,
3798                                                  us, tbl, FALSE, NULL,
3799                                                  -100.00, 100.00, 0.01, 0.1,
3800                                                  sp_text_vert_kern_changed);
3801                 gtk_widget_set_size_request (hb, 45, 0);
3802                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3803             }
3804         }
3806         // add the units menu
3807         gtk_widget_show(us);
3808         gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3809         gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3810     }
3812     // letter rotation
3813     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3814     {
3815         {
3816             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3817             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3818             gtk_container_add (GTK_CONTAINER (hb), image);
3819             gtk_widget_show(image);
3820             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3821         }
3822         {
3823             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3824                                              "tools.text", "letter_rotation", 0,
3825                                              us, tbl, FALSE, NULL,
3826                                              -180.0, 180.0, 0.1, 0.1,
3827                                              sp_text_letter_rotation_changed, 0.1, 1);
3828             gtk_widget_set_size_request (hb, 45, 0);
3829             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3830         }
3831         // rotation degree label
3832         {
3833             GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3834             gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3835         }
3836     }
3837         
3838     // Remove Manual Kerns
3839     {
3840         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3841         GtkWidget *button = gtk_button_new ();
3842         gtk_container_add (GTK_CONTAINER (button), px);
3843         gtk_widget_show(button);
3844         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3845         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3846         gtk_widget_set_sensitive(button, TRUE);
3847         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3848     }
3849 #endif
3851     gtk_widget_show_all (tbl);
3852     return tbl;
3854 } // end of sp_text_toolbox_new()
3856 }//<unnamed> namespace
3859 //#########################
3860 //##  Connector Toolbox  ##
3861 //#########################
3863 static void sp_connector_path_set_avoid(void)
3865     cc_selection_set_avoid(true);
3869 static void sp_connector_path_set_ignore(void)
3871     cc_selection_set_avoid(false);
3876 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3878     // quit if run by the _changed callbacks
3879     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3880         return;
3881     }
3882         
3883     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3884             "desktop");
3885     SPDocument *doc = sp_desktop_document(desktop);
3887     if (!sp_document_get_undo_sensitive(doc))
3888     {
3889         return;
3890     }
3892     // in turn, prevent callbacks from responding
3893     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3894     
3895     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3896     
3897     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3898     SP_OBJECT(desktop->namedview)->updateRepr();
3899     
3900     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3901     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3902         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3903         NR::Matrix m = NR::identity();
3904         avoid_item_move(&m, item);
3905     }
3907     if (items) {
3908         g_slist_free(items);
3909     }
3910     
3911     sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR, 
3912             _("Change connector spacing distance"));
3914     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3915     
3916     spinbutton_defocus(GTK_OBJECT(tbl));
3919 static void sp_connector_graph_layout(void)
3921     if (!SP_ACTIVE_DESKTOP) return;
3923     // hack for clones, see comment in align-and-distribute.cpp
3924     int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
3925     prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
3927     graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
3929     prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
3931     sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, /* TODO: annotate */ "toolbox.cpp:129");
3934 static void
3935 sp_directed_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
3937     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
3938         prefs_set_string_attribute("tools.connector", "directedlayout", 
3939                 "true");
3940     } else {
3941         prefs_set_string_attribute("tools.connector", "directedlayout", 
3942                 "false");
3943     }
3945 static void
3946 sp_nooverlaps_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
3948     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
3949         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout", 
3950                 "true");
3951     } else {
3952         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout", 
3953                 "false");
3954     }
3958 static void connector_length_changed(GtkAdjustment *adj, GtkWidget *tbl)
3960     prefs_set_double_attribute("tools.connector", "length", adj->value);
3961     spinbutton_defocus(GTK_OBJECT(tbl));
3964 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3965         gchar const *name, gchar const *old_value, gchar const *new_value,
3966         bool is_interactive, gpointer data)
3968     GtkWidget *tbl = GTK_WIDGET(data);
3970     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3971         return;
3972     }
3973     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3974         return;
3975     }
3977     GtkAdjustment *adj = (GtkAdjustment*)
3978             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3979     gdouble spacing = defaultConnSpacing;
3980     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3981     
3982     gtk_adjustment_set_value(adj, spacing);
3986 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3987     NULL, /* child_added */
3988     NULL, /* child_removed */
3989     connector_tb_event_attr_changed,
3990     NULL, /* content_changed */
3991     NULL  /* order_changed */
3992 };
3995 static GtkWidget *
3996 sp_connector_toolbox_new(SPDesktop *desktop)
3998     GtkTooltips *tt = gtk_tooltips_new();
3999     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
4000     
4001     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4002     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4004     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4005             AUX_BETWEEN_BUTTON_GROUPS);
4007     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4008             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
4009             tt, _("Make connectors avoid selected objects"));
4011     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4012             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
4013             tt, _("Make connectors ignore selected objects"));
4015     //  interval
4016     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4017             AUX_BETWEEN_BUTTON_GROUPS);
4019     // Spacing spinbox
4020     {
4021         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
4022                 _("The amount of space left around objects by auto-routing connectors"),
4023                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
4024                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
4025                 connector_spacing_changed, 1, 0);
4027         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
4028                 AUX_SPACING);
4029     }
4030     // Graph (connector network) layout
4031     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4032             "graph_layout", GTK_SIGNAL_FUNC(sp_connector_graph_layout),
4033             tt, _("Nicely arrange selected connector network"));
4034     // Default connector length spinbox
4035     {
4036         GtkWidget *connector_length = sp_tb_spinbutton(_("Length:"),
4037                 _("Ideal length for connectors when layout is applied"),
4038                 "tools.connector", "length", 100, NULL, tbl, TRUE,
4039                 "inkscape:connector-length", 10, 1000, 10.0, 100.0,
4040                 connector_length_changed, 1, 0);
4042         gtk_box_pack_start(GTK_BOX(tbl), connector_length, FALSE, FALSE,
4043                 AUX_SPACING);
4044     }
4045     gchar const *tbuttonstate;
4046     // Directed edges toggle button
4047     {
4048         GtkWidget *tbutton = gtk_toggle_button_new (); 
4049         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4050         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "directed_graph")); 
4051         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4052         gtk_tooltips_set_tip(tt, tbutton, _("Make connectors with end-markers (arrows) point downwards"), NULL);
4054         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4055         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_directed_graph_layout_toggled), tbl);
4056         tbuttonstate = prefs_get_string_attribute("tools.connector", "directedlayout");
4057         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton), 
4058                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4059     }
4060     // Avoid overlaps toggle button
4061     {
4062         GtkWidget *tbutton = gtk_toggle_button_new (); 
4063         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4064         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "remove_overlaps")); 
4065         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4066         gtk_tooltips_set_tip(tt, tbutton, _("Do not allow overlapping shapes"), NULL);
4068         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4069         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_nooverlaps_graph_layout_toggled), tbl);
4070         tbuttonstate = prefs_get_string_attribute("tools.connector", "avoidoverlaplayout");
4071         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton), 
4072                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4073     }
4075     gtk_widget_show_all(tbl);
4076     sp_set_font_size_smaller (tbl);
4077     
4078     // Code to watch for changes to the connector-spacing attribute in
4079     // the XML.
4080     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4081     g_assert(repr != NULL);
4082         
4083     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
4084             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
4085     
4086     if (oldrepr) { // remove old listener
4087         sp_repr_remove_listener_by_data(oldrepr, tbl);
4088         Inkscape::GC::release(oldrepr);
4089         oldrepr = NULL;
4090         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
4091     }
4093     if (repr) {
4094         g_object_set_data(G_OBJECT(tbl), "repr", repr);
4095         Inkscape::GC::anchor(repr);
4096         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
4097         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
4098     }
4099     
4100     return tbl;
4102 } // end of sp_connector_toolbox_new()
4105 /*
4106   Local Variables:
4107   mode:c++
4108   c-file-style:"stroustrup"
4109   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4110   indent-tabs-mode:nil
4111   fill-column:99
4112   End:
4113 */
4114 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :