Code

- improve hint for directed graph toggle
[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_pressure_state_changed(GtkWidget *button, gpointer data)
1990     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1993 static void
1994 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1996     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1998     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2001 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
2003     // FIXME: make defaults settable via Inkscape Options
2004     struct KeyValue {
2005         char const *key;
2006         double value;
2007     } const key_values[] = {
2008         {"mass", 0.02},
2009         {"drag", 1.0},
2010         {"angle", 30.0},
2011         {"width", 15},
2012         {"thinning", 0.1},
2013         {"tremor", 0.0},
2014         {"flatness", 0.9}
2015     };
2017     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2018         KeyValue const &kv = key_values[i];
2019         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2020         gtk_adjustment_set_value(&adj, kv.value);
2021     }
2023     spinbutton_defocus(GTK_OBJECT(tbl));
2026 static GtkWidget *
2027 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2029     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2030     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2031     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2033     GtkTooltips *tt = gtk_tooltips_new();
2034     GtkWidget *calligraphy_angle;
2036     //  interval
2037     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2039     /* Width */
2040     {
2041         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2042                                          "tools.calligraphic", "width", 15,
2043                                          NULL, tbl, TRUE, "altx-calligraphy",
2044                                          1, 100, 1.0, 10.0,
2045                                          sp_ddc_width_value_changed,  0.01, 0, 100);
2046         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2047     }
2049     /* Thinning */
2050     {
2051         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)"),
2052                                          "tools.calligraphic", "thinning", 0.1,
2053                                          NULL, tbl, FALSE, NULL,
2054                                          -1.0, 1.0, 0.01, 0.1,
2055                                          sp_ddc_velthin_value_changed, 0.01, 2);
2056         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2057     }
2059     //  interval
2060     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2062     /* Angle */
2063     {
2064         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2065                                              "tools.calligraphic", "angle", 30,
2066                                              NULL, tbl, TRUE, "calligraphy-angle",
2067                                              -90.0, 90.0, 1.0, 10.0,
2068                                              sp_ddc_angle_value_changed, 1, 0);
2069         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2070     }
2072     /* Fixation */
2073     {
2074         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2075                                          "tools.calligraphic", "flatness", 0.9,
2076                                          NULL, tbl, FALSE, NULL,
2077                                          0.0, 1.0, 0.01, 0.1,
2078                                          sp_ddc_flatness_value_changed, 0.01, 2);
2079         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2080     }
2082     //  interval
2083     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2085     /* Tremor */
2086     {
2087         GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2088                                          "tools.calligraphic", "tremor", 0.0,
2089                                          NULL, tbl, FALSE, NULL,
2090                                          0.0, 1.0, 0.01, 0.1,
2091                                          sp_ddc_tremor_value_changed, 0.01, 2);
2092         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2093     }
2094     /* Mass */
2095     {
2096         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2097                                          "tools.calligraphic", "mass", 0.02,
2098                                          NULL, tbl, FALSE, NULL,
2099                                          0.0, 1.0, 0.01, 0.1,
2100                                          sp_ddc_mass_value_changed, 0.01, 2);
2101         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2102     }
2104     /* Drag */
2105     {
2106         // TRANSLATORS: "drag" means "resistance" here
2107         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2108                                          "tools.calligraphic", "drag", 1,
2109                                          NULL, tbl, FALSE, NULL,
2110                                          0.0, 1.0, 0.01, 0.1,
2111                                          sp_ddc_drag_value_changed, 0.01, 2);
2112         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2113     }
2115     //  interval
2116     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2118     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2119     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2121     /* Use Pressure button */
2122     {
2123     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2124                                                  SP_BUTTON_TYPE_TOGGLE,
2125                                                  NULL,
2126                                                  "use_pressure",
2127                                                  _("Use the pressure of the input device to alter the width of the pen"),
2128                                                  tt);
2129     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2130     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2131     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2132     }
2134     /* Use Tilt button */
2135     {
2136     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2137                                                  SP_BUTTON_TYPE_TOGGLE,
2138                                                  NULL,
2139                                                  "use_tilt",
2140                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2141                                                  tt);
2142     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2143     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2144     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2145     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2146     }
2148     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2149     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2151     /* Reset */
2152     {
2153         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2154         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2155         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2156         gtk_widget_show(b);
2157         gtk_container_add(GTK_CONTAINER(hb), b);
2158         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2159         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2160     }
2163     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2164     swatch->setWatchedTool ("tools.calligraphic", true);
2165     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2166     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2168     gtk_widget_show_all(tbl);
2169     sp_set_font_size_smaller (tbl);
2171     return tbl;
2175 //########################
2176 //##    Circle / Arc    ##
2177 //########################
2179 static void 
2180 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2182     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2183     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2185     if (v1 == 0 && v2 == 0) {
2186         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2187             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2188             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2189         }
2190     } else {
2191         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2192         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2193     }
2196 static void
2197 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2199     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2201     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2202         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2203     }
2205     // quit if run by the attr_changed listener
2206     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2207         return;
2208     }
2210     // in turn, prevent listener from responding
2211     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2213     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2215     bool modmade = false;
2216     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2217          items != NULL;
2218          items = items->next)
2219     {
2220         SPItem *item = SP_ITEM(items->data);
2222         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2224             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2225             SPArc *arc = SP_ARC(item);
2227             if (!strcmp(value_name, "start"))
2228                 ge->start = (adj->value * M_PI)/ 180;
2229             else
2230                 ge->end = (adj->value * M_PI)/ 180;
2232             sp_genericellipse_normalize(ge);
2233             ((SPObject *)arc)->updateRepr();
2234             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2236             modmade = true;
2237         }
2238     }
2240     g_free(namespaced_name);
2242     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2244     sp_arctb_sensitivize (tbl, adj->value, other->value);
2246     if (modmade) {
2247         sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC, 
2248                                /* TODO: annotate */ "toolbox.cpp:2247");
2249     }
2251     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2252     spinbutton_defocus(GTK_OBJECT(tbl));
2254     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2258 static void
2259 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2261     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2264 static void
2265 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2267     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2270 static void
2271 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2273     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2275     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2276         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2277             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2278         } else {
2279             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2280         }
2281     }
2283     // quit if run by the attr_changed listener
2284     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2285         return;
2286     }
2288     // in turn, prevent listener from responding
2289     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2291     bool modmade = false;
2293     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2294         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2295              items != NULL;
2296              items = items->next)
2297         {
2298             if (SP_IS_ARC((SPItem *) items->data)) {
2299                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2300                 repr->setAttribute("sodipodi:open", "true");
2301                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2302                 modmade = true;
2303             }
2304         }
2305     } else {
2306         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2307              items != NULL;
2308              items = items->next)
2309         {
2310             if (SP_IS_ARC((SPItem *) items->data))    {
2311                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2312                 repr->setAttribute("sodipodi:open", NULL);
2313                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2314                 modmade = true;
2315             }
2316         }
2317     }
2319     if (modmade) {
2320         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, 
2321                          /* TODO: annotate */ "toolbox.cpp:2320");
2322     }
2324     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2326     spinbutton_defocus(GTK_OBJECT(tbl));
2329 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2331     GtkWidget *tbl = GTK_WIDGET(obj);
2333     GtkAdjustment *adj;
2334     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2335     gtk_adjustment_set_value(adj, 0.0);
2336     gtk_adjustment_value_changed(adj);
2338     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2339     gtk_adjustment_set_value(adj, 0.0);
2340     gtk_adjustment_value_changed(adj);
2342     spinbutton_defocus(GTK_OBJECT(tbl));
2345 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2346                                       gchar const *old_value, gchar const *new_value,
2347                                       bool is_interactive, gpointer data)
2349     GtkWidget *tbl = GTK_WIDGET(data);
2351     // quit if run by the _changed callbacks
2352     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2353         return;
2354     }
2356     // in turn, prevent callbacks from responding
2357     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2359     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2360     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2362     GtkAdjustment *adj1,*adj2;
2363     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2364     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2365     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2366     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2368     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2370     char const *openstr = NULL;
2371     openstr = repr->attribute("sodipodi:open");
2372     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2374     if (openstr) {
2375         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2376     } else {
2377         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2378     }
2380     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2383 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2384     NULL, /* child_added */
2385     NULL, /* child_removed */
2386     arc_tb_event_attr_changed,
2387     NULL, /* content_changed */
2388     NULL  /* order_changed */
2389 };
2392 static void
2393 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2395     int n_selected = 0;
2396     Inkscape::XML::Node *repr = NULL;
2397     Inkscape::XML::Node *oldrepr = NULL;
2399     for (GSList const *items = selection->itemList();
2400          items != NULL;
2401          items = items->next)
2402     {
2403         if (SP_IS_ARC((SPItem *) items->data)) {
2404             n_selected++;
2405             repr = SP_OBJECT_REPR((SPItem *) items->data);
2406         }
2407     }
2409     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2411     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2412     if (n_selected == 0) {
2413         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2414     } else if (n_selected == 1) {
2415         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2416         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2418         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2420         if (oldrepr) { // remove old listener
2421             sp_repr_remove_listener_by_data(oldrepr, tbl);
2422             Inkscape::GC::release(oldrepr);
2423             oldrepr = 0;
2424             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2425         }
2427         if (repr) {
2428             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2429             Inkscape::GC::anchor(repr);
2430             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2431             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2432         }
2433     } else {
2434         // FIXME: implement averaging of all parameters for multiple selected
2435         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2436         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2437         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2438     }
2442 static GtkWidget *
2443 sp_arc_toolbox_new(SPDesktop *desktop)
2445     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2447     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2448     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2450     GtkTooltips *tt = gtk_tooltips_new();
2452     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2454     /* Start */
2455     {
2456         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2457                                          "tools.shapes.arc", "start", 0.0,
2458                                          NULL, tbl, TRUE, "altx-arc",
2459                                          -360.0, 360.0, 1.0, 10.0,
2460                                          sp_arctb_start_value_changed);
2461         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2462     }
2464     /* End */
2465     {
2466         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2467                                          "tools.shapes.arc", "end", 0.0,
2468                                          NULL, tbl, FALSE, NULL,
2469                                          -360.0, 360.0, 1.0, 10.0,
2470                                          sp_arctb_end_value_changed);
2471         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2472     }
2474     /* Segments / Pie checkbox */
2475     {
2476         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2477         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2478         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2480         gchar const *openstr = NULL;
2481         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2482         if (!openstr || (openstr && !strcmp(openstr, "false")))
2483             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2484         else
2485             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2487         gtk_widget_show(fscb);
2488         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2489         gtk_container_add(GTK_CONTAINER(hb), fscb);
2490         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2491         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2492     }
2494     /* Make Whole */
2495     {
2496         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2497         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2498         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2499         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2500         gtk_widget_show(b);
2501         gtk_container_add(GTK_CONTAINER(hb), b);
2502         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2503         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2504     }
2506     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2507     // sensitivize make whole and open checkbox
2508     {
2509         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2510         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2511         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2512     }
2514     sigc::connection *connection = new sigc::connection(
2515         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2516         );
2517     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2519     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2520     swatch->setWatchedTool ("tools.shapes.arc", true);
2521     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2522     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2524     gtk_widget_show_all(tbl);
2525     sp_set_font_size_smaller (tbl);
2527     return tbl;
2533 // toggle button callbacks and updaters
2535 //########################
2536 //##      Dropper       ##
2537 //########################
2539 static void toggle_dropper_pick_alpha (GtkWidget *button, gpointer tbl) {
2540     prefs_set_int_attribute ("tools.dropper", "pick", 
2541         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
2542     GtkWidget *set_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "set_checkbox");
2543     if (set_checkbox) {
2544         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
2545             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), TRUE);
2546         } else {
2547             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), FALSE);
2548         }
2549     }
2552 static void toggle_dropper_set_alpha (GtkWidget *button, gpointer data) {
2553     prefs_set_int_attribute ("tools.dropper", "setalpha", 
2554         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
2558 /**
2559  * Copy the current saved desktop color to the clipboard as full hex + alpha
2560  * color representation. This is useful for passing values between various 
2561  * input boxes, or directly to xml.
2562  */
2563 /* static void
2564 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2566     GtkWidget *tbl = GTK_WIDGET(obj);
2567     
2568     SPDesktop *desktop = 
2569         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2571    
2572     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2573 }*/
2576 /**
2577  * Copies currently saved desktop color to the clipboard as a hex value. This 
2578  * is useful for editing webpages and needing a value quickly for web
2579  * colors.
2580  * 
2581  * TODO: When the toggle of the dropper is set to not mix color against 
2582  *       page background, this still just gets the color of the page and 
2583  *       doesn't get the actual mixed against background which is needed 
2584  *       for the hex value ppl. want for web pages, etc.
2585  */
2587 /* static void
2588 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2590     GtkWidget *tbl = GTK_WIDGET(obj);
2591     
2592     SPDesktop *desktop = 
2593         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2594     
2595     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2596 }*/
2599 /**
2600  * Sets the input boxes with the changed color and opacity. This is used as a 
2601  * callback for style changing.
2602  */
2603 /* static bool
2604 sp_style_changed (const SPCSSAttr *css, gpointer data)
2606     // GrDrag *drag = (GrDrag *) data;
2607     
2608     // set fill of text entry box
2609     if (css->attribute("fill"))
2610         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2611             css->attribute("fill")); 
2613     // set opacity of text entry box
2614     if (css->attribute("fill-opacity"))
2615         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2616             css->attribute("fill-opacity")); 
2617     
2618     // set fill of text entry box
2619     if (css->attribute("stroke"))
2620         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2621             css->attribute("stroke")); 
2623     // set opacity of text entry box
2624     if (css->attribute("stroke-opacity"))
2625         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2626             css->attribute("stroke-opacity"));
2627     return false;
2630 */
2633 /**
2634  * Dropper auxiliary toolbar construction and setup.
2635  *
2636  * TODO: Would like to add swatch of current color.
2637  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2638  *       can drag and drop places. Will provide a nice mixing palette.
2639  */
2640 static GtkWidget *
2641 sp_dropper_toolbox_new(SPDesktop *desktop)
2643     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2645     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2646     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2648     GtkTooltips *tt = gtk_tooltips_new();
2650     
2651     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2652                        AUX_BETWEEN_BUTTON_GROUPS);
2653     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2656     
2657     /* RGB Input Field */
2658  /*   {
2659         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2660         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2661         gtk_widget_show (dropper_rgba_label);
2662         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2663         
2664         dropper_rgb_entry = gtk_entry_new ();
2665         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2666         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2667         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2668         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2669                          _("Hexidecimal representation of last selected "
2670                            "color"), 
2671                          NULL);
2672         gtk_widget_show (dropper_rgb_entry);
2673         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2674         
2675         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2676                            AUX_BETWEEN_BUTTON_GROUPS);
2677     } */
2678     
2679     /* Opacity Input Field */
2680 /*    {
2681         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2682         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2683         gtk_widget_show (dropper_opacity_label);
2684         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2685         
2686         dropper_opacity_entry = gtk_entry_new ();
2687         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2688         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2689         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2690         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2691                          _("Opacity of last selected color"), 
2692                          NULL);
2693         gtk_widget_show (dropper_opacity_entry);
2694         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2695         
2696         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2697                            AUX_BETWEEN_BUTTON_GROUPS);
2698     } */
2699     
2700     
2701     /* Copy to Clipboard */
2702 /*    {
2703         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2704         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2705         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2706                                       "RGB + Alpha (RGBA) to "
2707                                       "clipboard"), 
2708                              NULL);
2709         gtk_widget_show(b);
2710         gtk_container_add(GTK_CONTAINER(hb), b);
2711         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2712             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2713         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2714                            AUX_BETWEEN_BUTTON_GROUPS);
2715     } */
2718     /* Copy to Clipboard as HEX */
2719 /*    {
2720         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2721         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2722         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2723                                       "hexidecimal RGB without alpha " 
2724                                       "to clipboard"), NULL);
2725         gtk_widget_show(b);
2726         gtk_container_add(GTK_CONTAINER(hb), b);
2727         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2728             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2729         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2730                            AUX_BETWEEN_BUTTON_GROUPS);
2731     } */
2732     
2733     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2734     
2735     {
2736         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2738         GtkWidget *button = gtk_check_button_new_with_label(_("Pick alpha"));
2739         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);
2740         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2741                                       prefs_get_int_attribute ("tools.dropper", 
2742                                                                "pick", 1));
2743         gtk_widget_show(button);
2744         gtk_container_add (GTK_CONTAINER (hb), button);
2745         gtk_object_set_data(GTK_OBJECT(tbl), "pick_checkbox", button);
2746         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_pick_alpha), tbl);
2747         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2748                    AUX_BETWEEN_BUTTON_GROUPS);
2749     }
2751     {
2752         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2754         GtkWidget *button = gtk_check_button_new_with_label(_("Set alpha"));
2755         gtk_tooltips_set_tip(tt, button, _("If alpha was picked, assign it to selection as fill or stroke transparency"), NULL);
2756         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2757                                       prefs_get_int_attribute ("tools.dropper", 
2758                                                                "setalpha", 1));
2759         gtk_widget_show(button);
2760         gtk_container_add (GTK_CONTAINER (hb), button);
2761         gtk_object_set_data(GTK_OBJECT(tbl), "set_checkbox", button);
2762         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_set_alpha), tbl);
2764         // make sure it's disabled if we're not picking alpha
2765         GtkWidget *pick_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "pick_checkbox");
2766         if (pick_checkbox) {
2767             if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pick_checkbox))) {
2768                 gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
2769             } else {
2770                 gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
2771             }
2772         }
2774         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2775                    AUX_BETWEEN_BUTTON_GROUPS);
2776     }
2777    
2778     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2779     
2781     // where new gtkmm stuff should go
2782     
2783     gtk_widget_show_all(tbl);
2784     sp_set_font_size_smaller (tbl);
2786     /*
2787     sigc::connection *connection = new sigc::connection(
2788         desktop->connectSetStyle(
2789             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2790                        desktop)) ); 
2791     
2792     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2793                      connection); */
2794     
2795     return tbl;
2799 //########################
2800 //##    Text Toolbox    ##
2801 //########################
2802 /*
2803 static void
2804 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2806     //Call back for letter sizing spinbutton
2809 static void
2810 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2812     //Call back for line height spinbutton
2815 static void
2816 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2818     //Call back for horizontal kerning spinbutton
2821 static void
2822 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2824     //Call back for vertical kerning spinbutton
2827 static void
2828 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2830     //Call back for letter rotation spinbutton
2831 }*/
2833 namespace {
2835 bool visible = false;
2837 void
2838 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2841     SPStyle *query =
2842         sp_style_new ();
2844     int result_family =
2845         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); 
2847     int result_style =
2848         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); 
2850     int result_numbers =
2851         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2853     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2855     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2856     if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2857     {
2858         Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
2860         if (repr)
2861         {
2862             sp_style_read_from_repr (query, repr);
2863         }
2864         else
2865         {
2866             return;
2867         }
2868     }
2870     if (query->text)
2871     {
2872         if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
2873             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
2874             gtk_entry_set_text (GTK_ENTRY (entry), "");
2876         } else if (query->text->font_family.value) {
2878             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
2879             gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
2881             Gtk::TreePath path;
2882             try {
2883                 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2884             } catch (...) {
2885                 return;
2886             }
2888             GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
2889             GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
2891             g_object_set_data (G_OBJECT (tselection), "block", gpointer(1)); 
2893             gtk_tree_selection_select_path (tselection, path.gobj());
2894             gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
2896             g_object_set_data (G_OBJECT (tselection), "block", gpointer(0)); 
2897         }
2899         //Size
2900         GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
2901         char *str = g_strdup_printf ("%.5g", query->font_size.computed);
2902         g_object_set_data (tbl, "size-block", gpointer(1)); 
2903         gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
2904         g_object_set_data (tbl, "size-block", gpointer(0)); 
2905         free (str);
2907         //Anchor
2908         if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
2909         {
2910             GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
2911             g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2912             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2913             g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2914         }
2915         else
2916         {
2917             if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
2918             {
2919                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
2920                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2921                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2922                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2923             }
2924             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
2925             {
2926                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
2927                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2928                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2929                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2930             }
2931             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
2932             {
2933                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
2934                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2935                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2936                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2937             }
2938         }
2940         //Style
2941         {
2942             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
2944             gboolean active = gtk_toggle_button_get_active (button);
2945             gboolean check  = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700); 
2947             if (active != check) 
2948             {
2949                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2950                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2951                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2952             }
2953         }
2955         {
2956             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
2958             gboolean active = gtk_toggle_button_get_active (button);
2959             gboolean check  = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL); 
2961             if (active != check)
2962             {
2963                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2964                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2965                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2966             }
2967         }
2969         //Orientation
2970         //locking both buttons, changing one affect all group (both)
2971         GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
2972         g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2973         
2974         GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
2975         g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
2976         
2977         if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
2978         {
2979             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2980         }
2981         else
2982         {
2983             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
2984         }
2985         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2986         g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
2987     }
2990 void
2991 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl) 
2993     sp_text_toolbox_selection_changed (selection, tbl); 
2996 void
2997 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
2999     sp_text_toolbox_selection_changed (NULL, tbl); 
3002 void
3003 sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
3004                                 GObject             *tbl) 
3006     SPDesktop    *desktop = SP_ACTIVE_DESKTOP;
3007     GtkTreeModel *model = 0;
3008     GtkWidget    *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3009     GtkWidget    *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3010     GtkTreeIter   iter;
3011     char         *family = 0;
3013     gdk_pointer_ungrab (GDK_CURRENT_TIME);
3014     gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3016     if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3017         return;
3018     }
3020     gtk_tree_model_get (model, &iter, 0, &family, -1);
3022     if (g_object_get_data (G_OBJECT (selection), "block"))
3023     {
3024         gtk_entry_set_text (GTK_ENTRY (entry), family);
3025         return;
3026     }
3027         
3028     gtk_widget_hide (popdown);
3029     visible = false;
3031     gtk_entry_set_text (GTK_ENTRY (entry), family);
3033     SPStyle *query =
3034         sp_style_new ();
3036     int result_numbers =
3037         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3039     SPCSSAttr *css = sp_repr_css_attr_new (); 
3040     sp_repr_css_set_property (css, "font-family", family); 
3042     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3043     if (result_numbers == QUERY_STYLE_NOTHING)
3044     {
3045         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3046         sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3047     }
3048     else
3049     {
3050         sp_desktop_set_style (desktop, css, true, true);
3051     }
3053     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3054                       /* TODO: annotate */ "toolbox.cpp:3024");
3055     sp_repr_css_attr_unref (css);
3056     free (family);
3057     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
3059     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3062 void
3063 sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
3064                                        GObject      *tbl) 
3066     const char *family = gtk_entry_get_text (entry);
3068     try {    
3069         Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3070         GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3071         GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3072         gtk_tree_selection_select_path (selection, path.gobj());
3073         gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3074         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
3075     } catch (...) {
3076         if (family && strlen (family))
3077         {
3078             gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3079         }
3080     }
3083 void
3084 sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
3085                                    gpointer          data)
3087     if (g_object_get_data (G_OBJECT (button), "block")) return;
3088     if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3089     int prop = GPOINTER_TO_INT(data); 
3091     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3092     SPCSSAttr *css = sp_repr_css_attr_new (); 
3094     switch (prop)
3095     {
3096         case 0:
3097         {
3098             sp_repr_css_set_property (css, "text-anchor", "start"); 
3099             sp_repr_css_set_property (css, "text-align", "start"); 
3100             break;
3101         }
3102         case 1:
3103         {
3104             sp_repr_css_set_property (css, "text-anchor", "middle"); 
3105             sp_repr_css_set_property (css, "text-align", "center"); 
3106             break;
3107         }
3109         case 2:
3110         {
3111             sp_repr_css_set_property (css, "text-anchor", "end"); 
3112             sp_repr_css_set_property (css, "text-align", "end"); 
3113             break;
3114         }
3116         case 3:
3117         {
3118             sp_repr_css_set_property (css, "text-anchor", "start"); 
3119             sp_repr_css_set_property (css, "text-align", "justify"); 
3120             break;
3121         }
3122     }
3124     SPStyle *query =
3125         sp_style_new ();
3126     int result_numbers =
3127         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3129     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3130     if (result_numbers == QUERY_STYLE_NOTHING)
3131     {
3132         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3133     }
3135     sp_desktop_set_style (desktop, css, true, true);
3136     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3137                       /* TODO: annotate */ "toolbox.cpp:3107");
3138     sp_repr_css_attr_unref (css);
3140     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3143 void
3144 sp_text_toolbox_style_toggled (GtkToggleButton  *button,
3145                                gpointer          data)
3147     if (g_object_get_data (G_OBJECT (button), "block")) return;
3149     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3150     SPCSSAttr   *css        = sp_repr_css_attr_new (); 
3151     int          prop       = GPOINTER_TO_INT(data); 
3152     bool         active     = gtk_toggle_button_get_active (button);
3155     switch (prop)
3156     {
3157         case 0:
3158         {
3159             sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" ); 
3160             break;
3161         }
3163         case 1:
3164         {
3165             sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal"); 
3166             break;
3167         }
3168     }
3170     SPStyle *query =
3171         sp_style_new ();
3172     int result_numbers =
3173         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3175     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3176     if (result_numbers == QUERY_STYLE_NOTHING)
3177     {
3178         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3179     }
3181     sp_desktop_set_style (desktop, css, true, true);
3182     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3183                       /* TODO: annotate */ "toolbox.cpp:3153");
3184     sp_repr_css_attr_unref (css);
3186     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3189 void
3190 sp_text_toolbox_orientation_toggled (GtkRadioButton  *button,
3191                                      gpointer         data)
3193     if (g_object_get_data (G_OBJECT (button), "block")) {
3194         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3195         return;
3196     }
3197     
3198     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3199     SPCSSAttr   *css        = sp_repr_css_attr_new (); 
3200     int          prop       = GPOINTER_TO_INT(data); 
3202     switch (prop)
3203     {
3204         case 0:
3205         {
3206             sp_repr_css_set_property (css, "writing-mode", "lr");
3207             break;
3208         }
3210         case 1:
3211         {
3212             sp_repr_css_set_property (css, "writing-mode", "tb"); 
3213             break;
3214         }
3215     }
3217     SPStyle *query =
3218         sp_style_new ();
3219     int result_numbers =
3220         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3222     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3223     if (result_numbers == QUERY_STYLE_NOTHING)
3224     {
3225         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3226     }
3228     sp_desktop_set_style (desktop, css, true, true);
3229     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3230                       /* TODO: annotate */ "toolbox.cpp:3200");
3231     sp_repr_css_attr_unref (css);
3233     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3236 gboolean
3237 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3239     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3240     if (!desktop) return FALSE;
3242     switch (get_group0_keyval (event)) {
3243         case GDK_Escape: // defocus
3244             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3245             return TRUE; // I consumed the event
3246             break;
3247         case GDK_Return: // defocus
3248         case GDK_KP_Enter:
3249             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3250             return TRUE; // I consumed the event
3251             break;
3252     }
3253     return FALSE;
3256 gboolean
3257 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
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             sp_text_toolbox_selection_changed (NULL, tbl); // update
3266             return TRUE; // I consumed the event
3267             break;
3268     }
3269     return FALSE;
3272 gboolean
3273 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3275     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3276     if (!desktop) return FALSE;
3278     switch (get_group0_keyval (event)) {
3279         case GDK_Escape: // defocus
3280             gtk_widget_hide (w);
3281             visible = false;
3282             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3283             return TRUE; // I consumed the event
3284             break;
3285     }
3286     return FALSE;
3290 void
3291 sp_text_toolbox_size_changed  (GtkComboBox *cbox,
3292                                GObject     *tbl) 
3294     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3296     if (g_object_get_data (tbl, "size-block")) return;
3298 #if GTK_CHECK_VERSION(2,6,0)
3299     char *text = gtk_combo_box_get_active_text (cbox);
3300 #else // GTK_CHECK_VERSION(2,6,0)
3301     GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3302     GtkTreeIter iter;
3303     char *text = NULL;
3305     if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3306         gtk_tree_model_get (model, &iter, 0, &text, -1);
3307 #endif // GTK_CHECK_VERSION(2,6,0)
3309     SPCSSAttr *css = sp_repr_css_attr_new (); 
3310     sp_repr_css_set_property (css, "font-size", text); 
3311     free (text);
3313     SPStyle *query =
3314         sp_style_new ();
3315     int result_numbers =
3316         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3318     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3319     if (result_numbers == QUERY_STYLE_NOTHING)
3320     {
3321         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3322     }
3324     sp_desktop_set_style (desktop, css, true, true);
3325     sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE, 
3326                             /* TODO: annotate */ "toolbox.cpp:3296");
3327     sp_repr_css_attr_unref (css);
3330     if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3331         gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3334 void
3335 sp_text_toolbox_text_popdown_clicked    (GtkButton          *button,
3336                                          GObject            *tbl)
3338     GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3339     GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3340     int x, y;
3342     if (!visible)
3343     {
3344         gdk_window_get_origin (widget->window, &x, &y);
3345         gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space 
3346         gtk_widget_show_all (popdown);
3348         gdk_pointer_grab (widget->window, TRUE,
3349                           GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3350                                         GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3351                                         GDK_POINTER_MOTION_MASK),
3352                           NULL, NULL, GDK_CURRENT_TIME);
3354         gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3356         visible = true;
3357     }
3358     else
3359     {
3360         gdk_pointer_ungrab (GDK_CURRENT_TIME);
3361         gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3362         gtk_widget_hide (popdown);
3363         visible = false;
3364     }
3367 gboolean
3368 sp_text_toolbox_entry_focus_in  (GtkWidget        *entry,
3369                                  GdkEventFocus    *event,
3370                                  GObject          *tbl)
3372     gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3373     return FALSE;
3376 gboolean
3377 sp_text_toolbox_popdown_focus_out (GtkWidget        *popdown,
3378                                    GdkEventFocus    *event,
3379                                    GObject          *tbl)
3381     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3383     gtk_widget_hide (popdown);
3384     visible = false;
3385     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3386     return TRUE;
3389 void
3390 cell_data_func  (GtkTreeViewColumn *column,
3391                  GtkCellRenderer   *cell,
3392                  GtkTreeModel      *tree_model,
3393                  GtkTreeIter       *iter,
3394                  gpointer           data)
3396     char        *family,
3397         *family_escaped,
3398         *sample_escaped;
3400     static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3402     gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3404     family_escaped = g_markup_escape_text (family, -1);
3405     sample_escaped = g_markup_escape_text (sample, -1);
3406     
3407     std::stringstream markup; 
3408     markup << family_escaped << "  <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3409     g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3411     free (family);
3412     free (family_escaped);
3413     free (sample_escaped);
3416 GtkWidget*
3417 sp_text_toolbox_new (SPDesktop *desktop)
3419     GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
3421     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3422     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3424     GtkTooltips *tt = gtk_tooltips_new();
3425     Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3427     ////////////Family
3428     //Window
3429     GtkWidget   *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3430     gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3432     //Entry
3433     GtkWidget           *entry = gtk_entry_new ();
3434     gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3435     GtkEntryCompletion  *completion = gtk_entry_completion_new ();
3436     gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3437     gtk_entry_completion_set_text_column (completion, 0);
3438     gtk_entry_completion_set_minimum_key_length (completion, 1); 
3439     g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3440     gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3441     aux_toolbox_space (tbl, 1);
3442     gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3443         
3444     //Button
3445     GtkWidget   *button = gtk_button_new ();
3446     gtk_container_add       (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3447     gtk_box_pack_start      (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3449     //Popdown
3450     GtkWidget           *sw = gtk_scrolled_window_new (NULL, NULL);
3451     GtkWidget           *treeview = gtk_tree_view_new ();
3453     GtkCellRenderer     *cell = gtk_cell_renderer_text_new ();
3454     GtkTreeViewColumn   *column = gtk_tree_view_column_new ();
3455     gtk_tree_view_column_pack_start (column, cell, FALSE);
3456     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3457     gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3458     gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3460     gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3461     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3462 #if GTK_CHECK_VERSION(2,6,0)
3463     gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3464 #endif // GTK_CHECK_VERSION(2,6,0)
3466     //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3468     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); 
3469     gtk_container_add (GTK_CONTAINER (sw), treeview);
3471     gtk_container_add (GTK_CONTAINER (window), sw);
3472     gtk_widget_set_size_request (window, 300, 450);
3474     g_signal_connect (G_OBJECT (entry),  "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3475     g_signal_connect (G_OBJECT (entry),  "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3476     g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3478     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3480     g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3481     g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3483     GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3484     g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3486     g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3487     g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3488     g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3489     g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3490     g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3492     GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3493     aux_toolbox_space (tbl, 1);
3494     GtkWidget *box = gtk_event_box_new ();
3495     gtk_container_add (GTK_CONTAINER (box), image);
3496     gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3497     g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3498     GtkTooltips *tooltips = gtk_tooltips_new ();
3499     gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3500     gtk_widget_hide (GTK_WIDGET (box));
3501     g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3503     ////////////Size
3504     const char *sizes[] = {
3505         "4", "6", "8", "9", "10", "11", "12", "13", "14",
3506         "16", "18", "20", "22", "24", "28",
3507         "32", "36", "40", "48", "56", "64", "72", "144"
3508     };
3510     GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3511     for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3512     gtk_widget_set_size_request (cbox, 80, -1);
3513     aux_toolbox_space (tbl, 1);
3514     gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3515     g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3516     g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3517     gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3519     //spacer
3520     aux_toolbox_space (tbl, 4);
3521     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3523     ////////////Text anchor
3524     GtkWidget *group   = gtk_radio_button_new (NULL);
3525     GtkWidget *row     = gtk_hbox_new (FALSE, 4);
3526     g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3528     // left
3529     GtkWidget *rbutton = group;
3530     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3531     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3532     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3534     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3535     g_object_set_data   (G_OBJECT (tbl), "text-start", rbutton);
3536     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3537     gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3539     // center
3540     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3541     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3542     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3543     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3545     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3546     g_object_set_data   (G_OBJECT (tbl), "text-middle", rbutton);
3547     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1)); 
3548     gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3550     // right
3551     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3552     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3553     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3554     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3556     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3557     g_object_set_data   (G_OBJECT (tbl), "text-end", rbutton);
3558     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3559     gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3561     // fill
3562     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3563     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3564     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3565     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3567     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3568     g_object_set_data   (G_OBJECT (tbl), "text-fill", rbutton);
3569     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3570     gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3572     aux_toolbox_space (tbl, 1);
3573     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3575     //spacer
3576     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3578     ////////////Text style
3579     row = gtk_hbox_new (FALSE, 4);
3581     // bold 
3582     rbutton = gtk_toggle_button_new (); 
3583     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3584     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3585     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3586     gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3588     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3589     g_object_set_data   (G_OBJECT (tbl), "style-bold", rbutton);
3590     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3592     // italic
3593     rbutton = gtk_toggle_button_new (); 
3594     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3595     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3596     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3597     gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3599     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3600     g_object_set_data   (G_OBJECT (tbl), "style-italic", rbutton);
3601     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1)); 
3603     aux_toolbox_space (tbl, 1);
3604     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3606     //spacer
3607     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3609     ////////////Text orientation
3610     group   = gtk_radio_button_new (NULL);
3611     row     = gtk_hbox_new (FALSE, 4);
3612     g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3614     // horizontal
3615     rbutton = group;
3616     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3617     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR)); 
3618     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3619     gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3621     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3622     g_object_set_data   (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3623     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3625     // vertical
3626     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3627     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3628     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB)); 
3629     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3630     gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3632     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3633     g_object_set_data   (G_OBJECT (tbl), "orientation-vertical", rbutton);
3634     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1)); 
3635     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3638     //watch selection
3639     Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3641     sigc::connection *c_selection_changed =
3642         new sigc::connection (sp_desktop_selection (desktop)->connectChanged 
3643                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3644     pool->add_connection ("selection-changed", c_selection_changed);
3646     sigc::connection *c_selection_modified =
3647         new sigc::connection (sp_desktop_selection (desktop)->connectModified 
3648                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3649     pool->add_connection ("selection-modified", c_selection_modified);
3651     sigc::connection *c_subselection_changed =
3652         new sigc::connection (desktop->connectToolSubselectionChanged
3653                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3654     pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3656     Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3659 #if 0
3660     // horizontal
3661     {
3662         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3663         GtkWidget *b = group = gtk_radio_button_new (NULL);
3664         gtk_container_add (GTK_CONTAINER (b), px);
3665         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3666         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3667         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3668         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3669     }
3671     // vertical
3672     {
3673         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3674         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3675         gtk_container_add (GTK_CONTAINER (b), px);
3676         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3677         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3678         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3679         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3680     }
3682     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3684     // letter spacing
3685     {
3686         {
3687             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3688             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3689             gtk_container_add (GTK_CONTAINER (hb), image);
3690             gtk_widget_show(image);
3691             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3692         }
3693     
3694         {
3695             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3696                                              "tools.text", "letter_spacing", 0.0,
3697                                              us, tbl, FALSE, NULL,
3698                                              -1000.0, 1000.0, 0.1, 0.1,
3699                                              sp_text_letter_changed, 0.1, 1);
3700             gtk_widget_set_size_request (hb, 45, 6);
3701             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3702         }
3703     }
3705     // line spacing
3706     {
3707         {
3708             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3709             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3710             gtk_container_add (GTK_CONTAINER (hb), image);
3711             gtk_widget_show(image);
3712             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3713         }
3714     
3715         {
3716             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3717                                              "tools.text", "line_spacing", 0,
3718                                              us, tbl, FALSE, NULL,
3719                                              -1000.0, 1000.0, 0.1, 0.1,
3720                                              sp_text_line_changed, 0.1, 1);
3721             gtk_widget_set_size_request (hb, 45, 0);
3722             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3723         }
3724     }
3726     {
3727         // horizontal kerning/vertical kerning units menu: create
3728         GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3729         sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3730         sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3732         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3734         // horizontal kerning
3735         {
3736             {
3737                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3738                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3739                 gtk_container_add (GTK_CONTAINER (hb), image);
3740                 gtk_widget_show(image);
3741                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3742             }
3744             {
3745                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3746                                                  "tools.text", "horizontal_kerning", 0,
3747                                                  us, tbl, FALSE, NULL,
3748                                                  -100.00, 100.00, 0.01, 0.1,
3749                                                  sp_text_horiz_kern_changed);
3750                 gtk_widget_set_size_request (hb, 45, 0);
3751                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3752             }
3753         }
3755         // vertical kerning
3756         {
3757             {
3758                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3759                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3760                 gtk_container_add (GTK_CONTAINER (hb), image);
3761                 gtk_widget_show(image);
3762                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3763             }
3764     
3765             {
3766                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3767                                                  "tools.text", "vertical_kerning", 0,
3768                                                  us, tbl, FALSE, NULL,
3769                                                  -100.00, 100.00, 0.01, 0.1,
3770                                                  sp_text_vert_kern_changed);
3771                 gtk_widget_set_size_request (hb, 45, 0);
3772                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3773             }
3774         }
3776         // add the units menu
3777         gtk_widget_show(us);
3778         gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3779         gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3780     }
3782     // letter rotation
3783     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3784     {
3785         {
3786             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3787             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3788             gtk_container_add (GTK_CONTAINER (hb), image);
3789             gtk_widget_show(image);
3790             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3791         }
3792         {
3793             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3794                                              "tools.text", "letter_rotation", 0,
3795                                              us, tbl, FALSE, NULL,
3796                                              -180.0, 180.0, 0.1, 0.1,
3797                                              sp_text_letter_rotation_changed, 0.1, 1);
3798             gtk_widget_set_size_request (hb, 45, 0);
3799             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3800         }
3801         // rotation degree label
3802         {
3803             GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3804             gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3805         }
3806     }
3807         
3808     // Remove Manual Kerns
3809     {
3810         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3811         GtkWidget *button = gtk_button_new ();
3812         gtk_container_add (GTK_CONTAINER (button), px);
3813         gtk_widget_show(button);
3814         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3815         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3816         gtk_widget_set_sensitive(button, TRUE);
3817         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3818     }
3819 #endif
3821     gtk_widget_show_all (tbl);
3822     return tbl;
3824 } // end of sp_text_toolbox_new()
3826 }//<unnamed> namespace
3829 //#########################
3830 //##  Connector Toolbox  ##
3831 //#########################
3833 static void sp_connector_path_set_avoid(void)
3835     cc_selection_set_avoid(true);
3839 static void sp_connector_path_set_ignore(void)
3841     cc_selection_set_avoid(false);
3846 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3848     // quit if run by the _changed callbacks
3849     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3850         return;
3851     }
3852         
3853     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3854             "desktop");
3855     SPDocument *doc = sp_desktop_document(desktop);
3857     if (!sp_document_get_undo_sensitive(doc))
3858     {
3859         return;
3860     }
3862     // in turn, prevent callbacks from responding
3863     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3864     
3865     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3866     
3867     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3868     SP_OBJECT(desktop->namedview)->updateRepr();
3869     
3870     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3871     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3872         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3873         NR::Matrix m = NR::identity();
3874         avoid_item_move(&m, item);
3875     }
3877     if (items) {
3878         g_slist_free(items);
3879     }
3880     
3881     sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR, 
3882             _("Change connector spacing distance"));
3884     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3885     
3886     spinbutton_defocus(GTK_OBJECT(tbl));
3889 static void sp_connector_graph_layout(void)
3891     if (!SP_ACTIVE_DESKTOP) return;
3893     // hack for clones, see comment in align-and-distribute.cpp
3894     int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
3895     prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
3897     graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
3899     prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
3901     sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, /* TODO: annotate */ "toolbox.cpp:129");
3904 static void
3905 sp_directed_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
3907     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
3908         prefs_set_string_attribute("tools.connector", "directedlayout", 
3909                 "true");
3910     } else {
3911         prefs_set_string_attribute("tools.connector", "directedlayout", 
3912                 "false");
3913     }
3915 static void
3916 sp_nooverlaps_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
3918     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
3919         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout", 
3920                 "true");
3921     } else {
3922         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout", 
3923                 "false");
3924     }
3928 static void connector_length_changed(GtkAdjustment *adj, GtkWidget *tbl)
3930     prefs_set_double_attribute("tools.connector", "length", adj->value);
3931     spinbutton_defocus(GTK_OBJECT(tbl));
3934 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3935         gchar const *name, gchar const *old_value, gchar const *new_value,
3936         bool is_interactive, gpointer data)
3938     GtkWidget *tbl = GTK_WIDGET(data);
3940     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3941         return;
3942     }
3943     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3944         return;
3945     }
3947     GtkAdjustment *adj = (GtkAdjustment*)
3948             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3949     gdouble spacing = defaultConnSpacing;
3950     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3951     
3952     gtk_adjustment_set_value(adj, spacing);
3956 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3957     NULL, /* child_added */
3958     NULL, /* child_removed */
3959     connector_tb_event_attr_changed,
3960     NULL, /* content_changed */
3961     NULL  /* order_changed */
3962 };
3965 static GtkWidget *
3966 sp_connector_toolbox_new(SPDesktop *desktop)
3968     GtkTooltips *tt = gtk_tooltips_new();
3969     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3970     
3971     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3972     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3974     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3975             AUX_BETWEEN_BUTTON_GROUPS);
3977     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3978             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3979             tt, _("Make connectors avoid selected objects"));
3981     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3982             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3983             tt, _("Make connectors ignore selected objects"));
3985     //  interval
3986     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3987             AUX_BETWEEN_BUTTON_GROUPS);
3989     // Spacing spinbox
3990     {
3991         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3992                 _("The amount of space left around objects by auto-routing connectors"),
3993                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3994                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3995                 connector_spacing_changed, 1, 0);
3997         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3998                 AUX_SPACING);
3999     }
4000     // Graph (connector network) layout
4001     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4002             "graph_layout", GTK_SIGNAL_FUNC(sp_connector_graph_layout),
4003             tt, _("Nicely arrange selected connector network"));
4004     // Default connector length spinbox
4005     {
4006         GtkWidget *connector_length = sp_tb_spinbutton(_("Length:"),
4007                 _("Ideal length for connectors when layout is applied"),
4008                 "tools.connector", "length", 100, NULL, tbl, TRUE,
4009                 "inkscape:connector-length", 10, 1000, 10.0, 100.0,
4010                 connector_length_changed, 1, 0);
4012         gtk_box_pack_start(GTK_BOX(tbl), connector_length, FALSE, FALSE,
4013                 AUX_SPACING);
4014     }
4015     gchar const *tbuttonstate;
4016     // Directed edges toggle button
4017     {
4018         GtkWidget *tbutton = gtk_toggle_button_new (); 
4019         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4020         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "directed_graph")); 
4021         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4022         gtk_tooltips_set_tip(tt, tbutton, _("Make connectors with end-markers (arrows) point downwards"), NULL);
4024         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4025         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_directed_graph_layout_toggled), tbl);
4026         tbuttonstate = prefs_get_string_attribute("tools.connector", "directedlayout");
4027         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton), 
4028                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4029     }
4030     // Avoid overlaps toggle button
4031     {
4032         GtkWidget *tbutton = gtk_toggle_button_new (); 
4033         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4034         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "remove_overlaps")); 
4035         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4036         gtk_tooltips_set_tip(tt, tbutton, _("Do not allow overlapping shapes"), NULL);
4038         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4039         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_nooverlaps_graph_layout_toggled), tbl);
4040         tbuttonstate = prefs_get_string_attribute("tools.connector", "avoidoverlaplayout");
4041         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton), 
4042                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4043     }
4045     gtk_widget_show_all(tbl);
4046     sp_set_font_size_smaller (tbl);
4047     
4048     // Code to watch for changes to the connector-spacing attribute in
4049     // the XML.
4050     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4051     g_assert(repr != NULL);
4052         
4053     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
4054             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
4055     
4056     if (oldrepr) { // remove old listener
4057         sp_repr_remove_listener_by_data(oldrepr, tbl);
4058         Inkscape::GC::release(oldrepr);
4059         oldrepr = NULL;
4060         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
4061     }
4063     if (repr) {
4064         g_object_set_data(G_OBJECT(tbl), "repr", repr);
4065         Inkscape::GC::anchor(repr);
4066         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
4067         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
4068     }
4069     
4070     return tbl;
4072 } // end of sp_connector_toolbox_new()
4075 /*
4076   Local Variables:
4077   mode:c++
4078   c-file-style:"stroustrup"
4079   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4080   indent-tabs-mode:nil
4081   fill-column:99
4082   End:
4083 */
4084 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :