Code

7ff4f115e2e00d4ef5732fdb84f0442d1d822c7f
[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"
80 #include "mod360.h"
82 #include "toolbox.h"
84 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
85 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
87 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
88 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
89 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
90 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
91 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
92 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
93 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
94 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
95 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
96 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
97 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
98 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
100 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
103 static struct {
104     gchar const *type_name;
105     gchar const *data_name;
106     sp_verb_t verb;
107     sp_verb_t doubleclick_verb;
108 } const tools[] = {
109     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
110     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
111     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
112     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
113     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
114     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
115     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
116     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
117     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
118     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
119     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
120     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
121     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
122     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
123     { NULL, NULL, 0, 0 }
124 };
126 static struct {
127     gchar const *type_name;
128     gchar const *data_name;
129     GtkWidget *(*create_func)(SPDesktop *desktop);
130 } const aux_toolboxes[] = {
131     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
132     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
133     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
134     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
135     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
136     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
137     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
138     { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
139     { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
140     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
141     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
142     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
143     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
144     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
145     { NULL, NULL, NULL }
146 };
148 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
150 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
151 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
153 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
154 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
156 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
157 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
159 /* Global text entry widgets necessary for update */
160 /* GtkWidget *dropper_rgb_entry, 
161           *dropper_opacity_entry ; */
162 // should be made a private member once this is converted to class
164 static void delete_connection(GObject *obj, sigc::connection *connection) {
165     connection->disconnect();
166     delete connection;
169 static GtkWidget *
170 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
171                       GtkTooltips *tt, gchar const *tip)
173     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
174     gtk_widget_show(b);
175     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
176     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
178     return b;
181 GtkWidget *
182 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
183                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
184                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
186     SPAction *action = verb->get_action(view);
187     if (!action) return NULL;
189     SPAction *doubleclick_action;
190     if (doubleclick_verb)
191         doubleclick_action = doubleclick_verb->get_action(view);
192     else
193         doubleclick_action = NULL;
195     /* fixme: Handle sensitive/unsensitive */
196     /* fixme: Implement sp_button_new_from_action */
197     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
198     gtk_widget_show(b);
199     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
201     return b;
204 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
205                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
207     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
210 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
211                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
213     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
216 GtkWidget *
217 sp_tool_toolbox_new()
219     GtkTooltips *tt = gtk_tooltips_new();
220     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
222     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
223     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
225     gtk_widget_set_sensitive(tb, FALSE);
227     GtkWidget *hb = gtk_handle_box_new();
228     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
229     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
230     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
232     gtk_container_add(GTK_CONTAINER(hb), tb);
233     gtk_widget_show(GTK_WIDGET(tb));
235     sigc::connection* conn = new sigc::connection;
236     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
238     return hb;
241 static void
242 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
244     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
245     gtk_widget_queue_resize(child);
248 static void
249 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
251     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
252     gtk_widget_queue_resize(child);
255 GtkWidget *
256 sp_aux_toolbox_new()
258     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
260     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
261     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
262     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
263     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
264     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
266     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
267     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
269     gtk_widget_set_sensitive(tb, FALSE);
271     GtkWidget *hb = gtk_handle_box_new();
272     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
273     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
274     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
276     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
277     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
279     gtk_container_add(GTK_CONTAINER(hb), tb);
280     gtk_widget_show(GTK_WIDGET(tb));
282     sigc::connection* conn = new sigc::connection;
283     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
285     return hb;
288 //####################################
289 //# Commands Bar
290 //####################################
292 GtkWidget *
293 sp_commands_toolbox_new()
295     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
297     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
298     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
299     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
300     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
301     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
303     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
304     gtk_widget_set_sensitive(tb, FALSE);
306     GtkWidget *hb = gtk_handle_box_new();
307     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
308     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
309     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
311     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
312     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
314     gtk_container_add(GTK_CONTAINER(hb), tb);
315     gtk_widget_show(GTK_WIDGET(tb));
317     sigc::connection* conn = new sigc::connection;
318     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
320     return hb;
324 //####################################
325 //# node editing callbacks
326 //####################################
328 void
329 sp_node_path_edit_add(void)
331     sp_node_selected_add_node();
334 void
335 sp_node_path_edit_delete(void)
337     sp_node_selected_delete();
340 void
341 sp_node_path_edit_delete_segment(void)
343     sp_node_selected_delete_segment();
346 void
347 sp_node_path_edit_break(void)
349     sp_node_selected_break();
352 void
353 sp_node_path_edit_join(void)
355     sp_node_selected_join();
358 void
359 sp_node_path_edit_join_segment(void)
361     sp_node_selected_join_segment();
364 void
365 sp_node_path_edit_toline(void)
367     sp_node_selected_set_line_type(NR_LINETO);
370 void
371 sp_node_path_edit_tocurve(void)
373     sp_node_selected_set_line_type(NR_CURVETO);
376 void
377 sp_node_path_edit_cusp(void)
379     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
382 void
383 sp_node_path_edit_smooth(void)
385     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
388 void
389 sp_node_path_edit_symmetrical(void)
391     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
394 static void toggle_show_handles (GtkWidget *button, gpointer data) {
395     bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
396     prefs_set_int_attribute ("tools.nodes", "show_handles",  show ? 1 : 0);
397     sp_nodepath_show_handles(show);
400 //################################
401 //##    Node Editing Toolbox    ##
402 //################################
404 static GtkWidget *
405 sp_node_toolbox_new(SPDesktop *desktop)
407     Inkscape::UI::View::View *view = desktop;
409     GtkTooltips *tt = gtk_tooltips_new();
410     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
412     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
414     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
415         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
416     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
417         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
419     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
421     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
422         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
423     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
424         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
426     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
427         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
429     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
430         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
432     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
434     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
435         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
437     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
438         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
440     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
441         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
443     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
445     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
446         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
448     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
449         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
451     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
453     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
455     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
457     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
459     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
460     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
462     {
463     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
464                                               SP_BUTTON_TYPE_TOGGLE,
465                                               NULL,
466                                               "nodes_show_handles",
467                                               _("Show the Bezier handles of selected nodes"),
468                                               tt);
469     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
470     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
471     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
472     }
474     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
475     gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
477     gtk_widget_show_all(tb);
479     return tb;
481 } // end of sp_node_toolbox_new()
484 //########################
485 //##    Zoom Toolbox    ##
486 //########################
488 static GtkWidget *
489 sp_zoom_toolbox_new(SPDesktop *desktop)
491     Inkscape::UI::View::View *view=desktop;
493     GtkTooltips *tt = gtk_tooltips_new();
494     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
496     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
497                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
499     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_IN), view, tt);
501     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_OUT), view, tt);
503     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
505     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);
507     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);
509     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);
511     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);
513     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
515     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PREV), view, tt);
517     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_NEXT), view, tt);
519     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
521     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);
523     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);
525     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);
527     gtk_widget_show_all(tb);
529     return tb;
531 } // end of sp_zoom_toolbox_new()
533 void
534 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
536     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")));
540 void
541 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
543     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")));
546 void
547 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
549     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")));
552 static void
553 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
555     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
556     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
558     if (old_desktop) {
559         GList *children, *iter;
561         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
562         for ( iter = children ; iter ; iter = iter->next ) {
563             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
564         }
565         g_list_free(children);
566     }
568     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
570     if (desktop) {
571         gtk_widget_set_sensitive(toolbox, TRUE);
572         setup_func(toolbox, desktop);
573         update_func(desktop, desktop->event_context, toolbox);
574         *conn = desktop->connectEventContextChanged 
575             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
576     } else {
577         gtk_widget_set_sensitive(toolbox, FALSE);
578     }
580 } // end of toolbox_set_desktop()
583 static void
584 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
586     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
587     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
588     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
590     for (int i = 0 ; tools[i].type_name ; i++ ) {
591         GtkWidget *button =
592             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
593                                                               SP_BUTTON_TYPE_TOGGLE,
594                                                               Inkscape::Verb::get(tools[i].verb),
595                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
596                                                               desktop,
597                                                               tooltips );
599         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
600                            (gpointer)button );
601     }
605 static void
606 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
608     gchar const *const tname = ( eventcontext
609                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
610                                  : NULL );
611     for (int i = 0 ; tools[i].type_name ; i++ ) {
612         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
613         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
614     }
617 static void
618 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
620     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
622     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
623         GtkWidget *sub_toolbox;
624         if (aux_toolboxes[i].create_func == NULL)
625             sub_toolbox = sp_empty_toolbox_new(desktop);
626         else
627             sub_toolbox = aux_toolboxes[i].create_func(desktop);
629         gtk_size_group_add_widget( grouper, sub_toolbox );
631         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
632         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
633     }
634     g_object_unref( G_OBJECT(grouper) );
637 static void
638 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
640     gchar const *tname = ( eventcontext
641                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
642                            : NULL );
643     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
644         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
645         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
646             gtk_widget_show_all(sub_toolbox);
647             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
648         } else {
649             gtk_widget_hide(sub_toolbox);
650         }
651     }
654 static void
655 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
657     Inkscape::UI::View::View *view = desktop;
659     GtkTooltips *tt = gtk_tooltips_new();
660     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
662     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
663     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
665     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
666     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
667     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
668     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
670     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
672     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
673     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
675     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
677     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
678     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
680     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
682     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
683     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
684     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
686     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
688     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
689     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
690     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
692     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
694     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
695     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
696     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
698     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
700     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
701     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
703     // disabled until we have icons for them:
705     //find
707     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
708     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
710     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
712     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
713     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
714     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
715     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), view, tt);
717     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
719     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_DISPLAY), view, tt);
720     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
722     gtk_widget_show_all(tb);
724     gtk_container_add(GTK_CONTAINER(toolbox), tb);
727 static void
728 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
732 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
734     gtk_widget_show(toolbox_toplevel);
735     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
737     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
738     if (!shown_toolbox) {
739         return;
740     }
741     gtk_widget_show(toolbox);
743     // need to show the spacer, or the padding will be off
744     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
745     gtk_widget_show(spacer);
747     gtk_widget_show_all(shown_toolbox);
750 void
751 aux_toolbox_space(GtkWidget *tb, gint space)
753     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
756 static GtkWidget *
757 sp_empty_toolbox_new(SPDesktop *desktop)
759     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
760     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
761     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
763     gtk_widget_show_all(tbl);
764     sp_set_font_size_smaller (tbl);
766     return tbl;
769 // helper UI functions
771 GtkWidget *
772 sp_tb_spinbutton(
773     gchar *label, gchar const *tooltip,
774     gchar const *path, gchar const *data, gdouble def,
775     GtkWidget *us,
776     GtkWidget *tbl,
777     gboolean altx, gchar const *altx_mark,
778     gdouble lower, gdouble upper, gdouble step, gdouble page,
779     void (*callback)(GtkAdjustment *, GtkWidget *),
780     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
782     GtkTooltips *tt = gtk_tooltips_new();
784     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
786     GtkWidget *l = gtk_label_new(label);
787     gtk_widget_show(l);
788     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
789     gtk_container_add(GTK_CONTAINER(hb), l);
791     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
792                                       lower, upper, step, page, page);
793     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
794     if (us)
795         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
797     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
798     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
799     if (altx)
800         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
801     gtk_widget_set_size_request(sb, 
802                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
803                                 AUX_SPINBUTTON_HEIGHT);
804     gtk_widget_show(sb);
805     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
806     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
807     gtk_container_add(GTK_CONTAINER(hb), sb);
808     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
810     return hb;
813 #define MODE_LABEL_WIDTH 70
815 //########################
816 //##       Star         ##
817 //########################
819 static void
820 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
822     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
824     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
825         // do not remember prefs if this call is initiated by an undo change, because undoing object
826         // creation sets bogus values to its attributes before it is deleted
827         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
828     }
830     // quit if run by the attr_changed listener
831     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
832         return;
833     }
835     // in turn, prevent listener from responding
836     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
838     bool modmade = false;
840     Inkscape::Selection *selection = sp_desktop_selection(desktop);
841     GSList const *items = selection->itemList();
842     for (; items != NULL; items = items->next) {
843         if (SP_IS_STAR((SPItem *) items->data)) {
844             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
845             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
846             sp_repr_set_svg_double(repr, "sodipodi:arg2",
847                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
848                                     + M_PI / (gint)adj->value));
849             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
850             modmade = true;
851         }
852     }
853     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
854                                    /* TODO: annotate */ "toolbox.cpp:854");
856     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
858     spinbutton_defocus(GTK_OBJECT(tbl));
861 static void
862 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
864     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
866     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
867         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
868     }
870     // quit if run by the attr_changed listener
871     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
872         return;
873     }
875     // in turn, prevent listener from responding
876     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
878     bool modmade = false;
879     Inkscape::Selection *selection = sp_desktop_selection(desktop);
880     GSList const *items = selection->itemList();
881     for (; items != NULL; items = items->next) {
882         if (SP_IS_STAR((SPItem *) items->data)) {
883             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
885             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
886             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
887             if (r2 < r1) {
888                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
889             } else {
890                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
891             }
893             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
894             modmade = true;
895         }
896     }
898     if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
899                                   /* TODO: annotate */ "toolbox.cpp:899");
901     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
903     spinbutton_defocus(GTK_OBJECT(tbl));
906 static void
907 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
909     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
911     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
912         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
913             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
914         } else {
915             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
916         }
917     }
919     // quit if run by the attr_changed listener
920     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
921         return;
922     }
924     // in turn, prevent listener from responding
925     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
927     Inkscape::Selection *selection = sp_desktop_selection(desktop);
928     GSList const *items = selection->itemList();
929     GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
930     bool modmade = false;
931     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
932         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
933         for (; items != NULL; items = items->next) {
934             if (SP_IS_STAR((SPItem *) items->data)) {
935                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
936                 repr->setAttribute("inkscape:flatsided", "true");
937                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
938                 modmade = true;
939             }
940         }
941     } else {
942         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
943         for (; items != NULL; items = items->next) {
944             if (SP_IS_STAR((SPItem *) items->data)) {
945                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
946                 repr->setAttribute("inkscape:flatsided", "false");
947                 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
948                 modmade = true;
949             }
950         }
951     }
952     if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
953                                   /* TODO: annotate */ "toolbox.cpp:953");
955     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
957     spinbutton_defocus(GTK_OBJECT(tbl));
960 static void
961 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
963     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
965     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
966         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
967     }
969     // quit if run by the attr_changed listener
970     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
971         return;
972     }
974     // in turn, prevent listener from responding
975     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
977     bool modmade = false;
979     Inkscape::Selection *selection = sp_desktop_selection(desktop);
980     GSList const *items = selection->itemList();
981     for (; items != NULL; items = items->next) {
982         if (SP_IS_STAR((SPItem *) items->data)) {
983             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
984             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
985             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
986             modmade = true;
987         }
988     }
989     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
990                                    /* TODO: annotate */ "toolbox.cpp:990");
992     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
994     spinbutton_defocus(GTK_OBJECT(tbl));
998 static void
999 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1001     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1003     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1004         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1005     }
1007     // quit if run by the attr_changed listener
1008     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1009         return;
1010     }
1012     // in turn, prevent listener from responding
1013     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1015     bool modmade = false;
1017     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1018     GSList const *items = selection->itemList();
1019     for (; items != NULL; items = items->next) {
1020         if (SP_IS_STAR((SPItem *) items->data)) {
1021             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1022             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1023             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1024             modmade = true;
1025         }
1026     }
1027     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR, 
1028                                    /* TODO: annotate */ "toolbox.cpp:1028");
1030     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1032     spinbutton_defocus(GTK_OBJECT(tbl));
1036 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1037                                        gchar const *old_value, gchar const *new_value,
1038                                        bool is_interactive, gpointer data)
1040     GtkWidget *tbl = GTK_WIDGET(data);
1042     // quit if run by the _changed callbacks
1043     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1044         return;
1045     }
1047     // in turn, prevent callbacks from responding
1048     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1050     GtkAdjustment *adj;
1052     if (!strcmp(name, "inkscape:randomized")) {
1053         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1054         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1055     } else if (!strcmp(name, "inkscape:rounded")) {
1056         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1057         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1058     } else if (!strcmp(name, "inkscape:flatsided")) {
1059         GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1060         GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1061         char const *flatsides = repr->attribute("inkscape:flatsided");
1062         if (flatsides && !strcmp(flatsides,"false" )) {
1063             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1064             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1065         } else {
1066             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1067             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1068         }
1069     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1070         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1071         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1072         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1073         if (r2 < r1) {
1074             gtk_adjustment_set_value(adj, r2/r1);
1075         } else {
1076             gtk_adjustment_set_value(adj, r1/r2);
1077         }
1078     } else if (!strcmp(name, "sodipodi:sides")) {
1079         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1080         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1081     }
1083     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1087 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1089     NULL, /* child_added */
1090     NULL, /* child_removed */
1091     star_tb_event_attr_changed,
1092     NULL, /* content_changed */
1093     NULL  /* order_changed */
1094 };
1097 /**
1098  *  \param selection Should not be NULL.
1099  */
1100 static void
1101 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1103     int n_selected = 0;
1104     Inkscape::XML::Node *repr = NULL;
1105     Inkscape::XML::Node *oldrepr = NULL;
1107     for (GSList const *items = selection->itemList();
1108          items != NULL;
1109          items = items->next)
1110     {
1111         if (SP_IS_STAR((SPItem *) items->data)) {
1112             n_selected++;
1113             repr = SP_OBJECT_REPR((SPItem *) items->data);
1114         }
1115     }
1117     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1119     if (n_selected == 0) {
1120         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1121     } else if (n_selected == 1) {
1122         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1124         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1125         if (oldrepr) { // remove old listener
1126             sp_repr_remove_listener_by_data(oldrepr, tbl);
1127             Inkscape::GC::release(oldrepr);
1128             oldrepr = 0;
1129             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1130         }
1132         if (repr) {
1133             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1134             Inkscape::GC::anchor(repr);
1135             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1136             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1137         }
1138     } else {
1139         // FIXME: implement averaging of all parameters for multiple selected stars
1140         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1141         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1142     }
1146 static void
1147 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1149     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1150     // callbacks to lump all the changes for all selected objects in one undo step
1152     GtkAdjustment *adj;
1154     // fixme: make settable in prefs!
1155     gint mag = 5;
1156     gdouble prop = 0.5;
1157     gboolean flat = FALSE;
1158     gdouble randomized = 0;
1159     gdouble rounded = 0;
1161     GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1162     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  flat);
1163     GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1164     gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1166     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1167     gtk_adjustment_set_value(adj, mag);
1168     gtk_adjustment_value_changed(adj);
1170     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1171     gtk_adjustment_set_value(adj, prop);
1172     gtk_adjustment_value_changed(adj);
1174     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1175     gtk_adjustment_set_value(adj, rounded);
1176     gtk_adjustment_value_changed(adj);
1178     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1179     gtk_adjustment_set_value(adj, randomized);
1180     gtk_adjustment_value_changed(adj);
1182     spinbutton_defocus(GTK_OBJECT(tbl));
1186 void
1187 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1189     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1190     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1191     GtkWidget *l = gtk_label_new(NULL);
1192     gtk_label_set_markup(GTK_LABEL(l), title);
1193     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1194     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1195     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1199 static GtkWidget *
1200 sp_star_toolbox_new(SPDesktop *desktop)
1202     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1204     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1205     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1207     GtkTooltips *tt = gtk_tooltips_new();
1209     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1211     gchar const *flatsidedstr = NULL;
1213     /* Flatsided checkbox */
1214     {
1215         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1216         GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1217         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1218         flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1219         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1220             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1221         else
1222             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1223         gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1224         gtk_widget_show(fscb);
1225         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1226         gtk_container_add(GTK_CONTAINER(hb), fscb);
1227         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1228         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1229     }
1231     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1233     /* Magnitude */
1234     {
1235         GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1236                                          "tools.shapes.star", "magnitude", 3,
1237                                          NULL, tbl, TRUE, "altx-star",
1238                                          3, 1024, 1, 1,
1239                                          sp_stb_magnitude_value_changed, 1, 0);
1240         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1241     }
1243     /* Spoke ratio */
1244     {
1245         GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1246                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1247                                          // Base radius is the same for the closest handle.
1248                                          _("Base radius to tip radius ratio"),
1249                                          "tools.shapes.star", "proportion", 0.5,
1250                                          NULL, tbl, FALSE, NULL,
1251                                          0.01, 1.0, 0.01, 0.1,
1252                                          sp_stb_proportion_value_changed);
1253         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1254         g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1255         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1256             gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1257         else
1258             gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1259     }
1261     /* Roundedness */
1262     {
1263         GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1264                                          "tools.shapes.star", "rounded", 0.0,
1265                                          NULL, tbl, FALSE, NULL,
1266                                          -100.0, 100.0, 0.01, 0.1,
1267                                          sp_stb_rounded_value_changed);
1268         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1269     }
1271     /* Randomization */
1272     {
1273         GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1274                                          "tools.shapes.star", "randomized", 0.0,
1275                                          NULL, tbl, FALSE, NULL,
1276                                          -10.0, 10.0, 0.001, 0.01,
1277                                          sp_stb_randomized_value_changed, 0.1, 3);
1278         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1279     }
1281     aux_toolbox_space(tbl, AUX_SPACING);
1283     /* Reset */
1284     {
1285         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1286         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1287         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1288         gtk_widget_show(b);
1289         gtk_container_add(GTK_CONTAINER(hb), b);
1290         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1291         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1292     }
1294     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1295     swatch->setWatchedTool ("tools.shapes.star", true);
1296     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1297     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1299     gtk_widget_show_all(tbl);
1300     sp_set_font_size_smaller (tbl);
1302     sigc::connection *connection = new sigc::connection(
1303         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1304         );
1305     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1307     return tbl;
1311 //########################
1312 //##       Rect         ##
1313 //########################
1315 static void 
1316 sp_rtb_sensitivize (GtkWidget *tbl)
1318     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1319     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1320     GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1322     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1323         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1324     } else {
1325         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1326     }
1330 static void
1331 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1332                           void (*setter)(SPRect *, gdouble))
1334     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1336     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1337     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1339     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1340         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1341     }
1343     // quit if run by the attr_changed listener
1344     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1345         return;
1346     }
1348     // in turn, prevent listener from responding
1349     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1351     bool modmade = false;
1352     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1353     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1354         if (SP_IS_RECT(items->data)) {
1355             if (adj->value != 0) {
1356                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1357             } else {
1358                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1359             }
1360             modmade = true;
1361         }
1362     }
1364     sp_rtb_sensitivize (tbl);
1366     if (modmade) {
1367         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT, 
1368                          /* TODO: annotate */ "toolbox.cpp:1368");
1369     }
1371     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1373     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1374     spinbutton_defocus(GTK_OBJECT(tbl));
1377 static void
1378 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1380     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1383 static void
1384 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1386     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1389 static void
1390 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1392     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1395 static void
1396 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1398     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1403 static void
1404 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1406     GtkWidget *tbl = GTK_WIDGET(obj);
1408     GtkAdjustment *adj;
1410     adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1411     gtk_adjustment_set_value(adj, 0.0);
1412     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1413     gtk_adjustment_value_changed(adj);
1415     adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1416     gtk_adjustment_set_value(adj, 0.0);
1417     gtk_adjustment_value_changed(adj);
1419     sp_rtb_sensitivize (tbl);
1421     spinbutton_defocus(GTK_OBJECT(tbl));
1424 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1425                                        gchar const *old_value, gchar const *new_value,
1426                                        bool is_interactive, gpointer data)
1428     GtkWidget *tbl = GTK_WIDGET(data);
1430     // quit if run by the _changed callbacks
1431     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1432         return;
1433     }
1435     // in turn, prevent callbacks from responding
1436     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1438     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1439     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1441     SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1442     if (SP_IS_RECT(item)) {
1443         {
1444             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1445             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1446             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1447         }
1449         {
1450             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1451             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1452             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1453         }
1455         {
1456             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1457             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1458             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1459         }
1461         {
1462             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1463             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1464             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1465         }
1466     }
1468     sp_rtb_sensitivize (tbl);
1470     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1474 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1475     NULL, /* child_added */
1476     NULL, /* child_removed */
1477     rect_tb_event_attr_changed,
1478     NULL, /* content_changed */
1479     NULL  /* order_changed */
1480 };
1482 /**
1483  *  \param selection should not be NULL.
1484  */
1485 static void
1486 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1488     int n_selected = 0;
1489     Inkscape::XML::Node *repr = NULL;
1490     SPItem *item = NULL;
1491     Inkscape::XML::Node *oldrepr = NULL;
1493     for (GSList const *items = selection->itemList();
1494          items != NULL;
1495          items = items->next) {
1496         if (SP_IS_RECT((SPItem *) items->data)) {
1497             n_selected++;
1498             item = (SPItem *) items->data;
1499             repr = SP_OBJECT_REPR(item);
1500         }
1501     }
1503     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1505     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1507     if (n_selected == 0) {
1508         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1510         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1511         gtk_widget_set_sensitive(w, FALSE);
1512         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1513         gtk_widget_set_sensitive(h, FALSE);
1515     } else if (n_selected == 1) {
1516         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1517         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1519         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1520         gtk_widget_set_sensitive(w, TRUE);
1521         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1522         gtk_widget_set_sensitive(h, TRUE);
1524         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1525         if (oldrepr) { // remove old listener
1526             sp_repr_remove_listener_by_data(oldrepr, tbl);
1527             Inkscape::GC::release(oldrepr);
1528             oldrepr = 0;
1529             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1530         }
1531         if (repr) {
1532             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1533             g_object_set_data(G_OBJECT(tbl), "item", item);
1534             Inkscape::GC::anchor(repr);
1535             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1536             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1537         }
1538     } else {
1539         // FIXME: implement averaging of all parameters for multiple selected
1540         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1541         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1542         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1543     }
1547 static GtkWidget *
1548 sp_rect_toolbox_new(SPDesktop *desktop)
1550     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1552     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1553     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1555     GtkTooltips *tt = gtk_tooltips_new();
1557     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1559     // rx/ry units menu: create
1560     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1561     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1562     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1563     // fixme: add % meaning per cent of the width/height
1565     /* W */
1566     {
1567         GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1568                                          "tools.shapes.rect", "width", 0,
1569                                          us, tbl, TRUE, "altx-rect",
1570                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1571                                          sp_rtb_width_value_changed);
1572         gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1573         gtk_widget_set_sensitive(hb, FALSE);
1574         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1575     }
1577     /* H */
1578     {
1579         GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1580                                          "tools.shapes.rect", "height", 0,
1581                                          us, tbl, FALSE, NULL,
1582                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1583                                          sp_rtb_height_value_changed);
1584         gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1585         gtk_widget_set_sensitive(hb, FALSE);
1586         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1587     }
1589     /* rx */
1590     {
1591         GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1592                                          "tools.shapes.rect", "rx", 0,
1593                                          us, tbl, FALSE, NULL,
1594                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1595                                          sp_rtb_rx_value_changed);
1596         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1597     }
1599     /* ry */
1600     {
1601         GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1602                                          "tools.shapes.rect", "ry", 0,
1603                                          us, tbl, FALSE, NULL,
1604                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1605                                          sp_rtb_ry_value_changed);
1606         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1607     }
1609     // add the units menu
1610     gtk_widget_show(us);
1611     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1612     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1614     /* Reset */
1615     {
1616         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1617         GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1618         gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1619         gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1620         gtk_widget_show(b);
1621         gtk_container_add(GTK_CONTAINER(hb), b);
1622         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1623         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1624     }
1626     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1627     swatch->setWatchedTool ("tools.shapes.rect", true);
1628     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1629     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1631     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1632     sp_rtb_sensitivize (tbl);
1634     gtk_widget_show_all(tbl);
1635     sp_set_font_size_smaller (tbl);
1637     sigc::connection *connection = new sigc::connection(
1638         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1639         );
1640     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1642     return tbl;
1645 //########################
1646 //##       Spiral       ##
1647 //########################
1649 static void
1650 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1652     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1654     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1655         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1656     }
1658     // quit if run by the attr_changed listener
1659     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1660         return;
1661     }
1663     // in turn, prevent listener from responding
1664     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1666     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1668     bool modmade = false;
1669     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1670          items != NULL;
1671          items = items->next)
1672     {
1673         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1674             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1675             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1676             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1677             modmade = true;
1678         }
1679     }
1681     g_free(namespaced_name);
1683     if (modmade) {
1684         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL, 
1685                          /* TODO: annotate */ "toolbox.cpp:1685");
1686     }
1688     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1690     spinbutton_defocus(GTK_OBJECT(tbl));
1693 static void
1694 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1696     sp_spl_tb_value_changed(adj, tbl, "revolution");
1699 static void
1700 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1702     sp_spl_tb_value_changed(adj, tbl, "expansion");
1705 static void
1706 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1708     sp_spl_tb_value_changed(adj, tbl, "t0");
1711 static void
1712 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1714     GtkWidget *tbl = GTK_WIDGET(obj);
1716     GtkAdjustment *adj;
1718     // fixme: make settable
1719     gdouble rev = 5;
1720     gdouble exp = 1.0;
1721     gdouble t0 = 0.0;
1723     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1724     gtk_adjustment_set_value(adj, rev);
1725     gtk_adjustment_value_changed(adj);
1727     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1728     gtk_adjustment_set_value(adj, exp);
1729     gtk_adjustment_value_changed(adj);
1731     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1732     gtk_adjustment_set_value(adj, t0);
1733     gtk_adjustment_value_changed(adj);
1735     spinbutton_defocus(GTK_OBJECT(tbl));
1739 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1740                                          gchar const *old_value, gchar const *new_value,
1741                                          bool is_interactive, gpointer data)
1743     GtkWidget *tbl = GTK_WIDGET(data);
1745     // quit if run by the _changed callbacks
1746     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1747         return;
1748     }
1750     // in turn, prevent callbacks from responding
1751     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1753     GtkAdjustment *adj;
1754     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1755     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1757     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1758     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1760     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1761     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1763     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1767 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1768     NULL, /* child_added */
1769     NULL, /* child_removed */
1770     spiral_tb_event_attr_changed,
1771     NULL, /* content_changed */
1772     NULL  /* order_changed */
1773 };
1775 static void
1776 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1778     int n_selected = 0;
1779     Inkscape::XML::Node *repr = NULL;
1780     Inkscape::XML::Node *oldrepr = NULL;
1782     for (GSList const *items = selection->itemList();
1783          items != NULL;
1784          items = items->next)
1785     {
1786         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1787             n_selected++;
1788             repr = SP_OBJECT_REPR((SPItem *) items->data);
1789         }
1790     }
1792     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1794     if (n_selected == 0) {
1795         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1796     } else if (n_selected == 1) {
1797         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1799         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1800         if (oldrepr) { // remove old listener
1801             sp_repr_remove_listener_by_data(oldrepr, tbl);
1802             Inkscape::GC::release(oldrepr);
1803             oldrepr = 0;
1804             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1805         }
1807         if (repr) {
1808             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1809             Inkscape::GC::anchor(repr);
1810             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1811             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1812         }
1813     } else {
1814         // FIXME: implement averaging of all parameters for multiple selected
1815         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1816         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1817     }
1821 static GtkWidget *
1822 sp_spiral_toolbox_new(SPDesktop *desktop)
1824     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1825     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1826     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1828     GtkTooltips *tt = gtk_tooltips_new();
1830     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1832     /* Revolution */
1833     {
1834         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1835                                          "tools.shapes.spiral", "revolution", 3.0,
1836                                          NULL, tbl, TRUE, "altx-spiral",
1837                                          0.01, 1024.0, 0.1, 1.0,
1838                                          sp_spl_tb_revolution_value_changed, 1, 2);
1839         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1840     }
1842     /* Expansion */
1843     {
1844         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1845                                          "tools.shapes.spiral", "expansion", 1.0,
1846                                          NULL, tbl, FALSE, NULL,
1847                                          0.0, 1000.0, 0.01, 1.0,
1848                                          sp_spl_tb_expansion_value_changed);
1849         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1850     }
1852     /* T0 */
1853     {
1854         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1855                                          "tools.shapes.spiral", "t0", 0.0,
1856                                          NULL, tbl, FALSE, NULL,
1857                                          0.0, 0.999, 0.01, 1.0,
1858                                          sp_spl_tb_t0_value_changed);
1859         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1860     }
1862     aux_toolbox_space(tbl, AUX_SPACING);
1864     /* Reset */
1865     {
1866         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1867         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1868         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1869         gtk_widget_show(b);
1870         gtk_container_add(GTK_CONTAINER(hb), b);
1871         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1872         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1873     }
1875     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1876     swatch->setWatchedTool ("tools.shapes.spiral", true);
1877     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1878     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1880     gtk_widget_show_all(tbl);
1881     sp_set_font_size_smaller (tbl);
1883     sigc::connection *connection = new sigc::connection(
1884         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1885         );
1886     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1888     return tbl;
1891 //########################
1892 //##     Pen/Pencil    ##
1893 //########################
1896 static GtkWidget *
1897 sp_pen_toolbox_new(SPDesktop *desktop)
1899     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1900     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1901     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1903     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1904     swatch->setWatchedTool ("tools.freehand.pen", true);
1905     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1906     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1908     gtk_widget_show_all(tbl);
1909     sp_set_font_size_smaller (tbl);
1911     return tbl;
1914 static GtkWidget *
1915 sp_pencil_toolbox_new(SPDesktop *desktop)
1917     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1918     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1919     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1921     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
1922     swatch->setWatchedTool ("tools.freehand.pencil", true);
1923     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1924     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
1926     gtk_widget_show_all(tbl);
1927     sp_set_font_size_smaller (tbl);
1929     return tbl;
1933 //########################
1934 //##     Calligraphy    ##
1935 //########################
1937 static void
1938 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1940     prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1941     spinbutton_defocus(GTK_OBJECT(tbl));
1944 static void
1945 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1947     prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1948     spinbutton_defocus(GTK_OBJECT(tbl));
1951 static void
1952 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1954     prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1955     spinbutton_defocus(GTK_OBJECT(tbl));
1958 static void
1959 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1961     prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1962     spinbutton_defocus(GTK_OBJECT(tbl));
1965 static void
1966 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1968     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1969     spinbutton_defocus(GTK_OBJECT(tbl));
1972 static void
1973 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1975     prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1976     spinbutton_defocus(GTK_OBJECT(tbl));
1979 static void
1980 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1982     prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1983     spinbutton_defocus(GTK_OBJECT(tbl));
1986 static void
1987 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1989     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1992 static void
1993 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1995     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1997     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2000 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
2002     // FIXME: make defaults settable via Inkscape Options
2003     struct KeyValue {
2004         char const *key;
2005         double value;
2006     } const key_values[] = {
2007         {"mass", 0.02},
2008         {"drag", 1.0},
2009         {"angle", 30.0},
2010         {"width", 15},
2011         {"thinning", 0.1},
2012         {"tremor", 0.0},
2013         {"flatness", 0.9}
2014     };
2016     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2017         KeyValue const &kv = key_values[i];
2018         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
2019         gtk_adjustment_set_value(&adj, kv.value);
2020     }
2022     spinbutton_defocus(GTK_OBJECT(tbl));
2025 static GtkWidget *
2026 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2028     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2029     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2030     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2032     GtkTooltips *tt = gtk_tooltips_new();
2033     GtkWidget *calligraphy_angle;
2035     //  interval
2036     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2038     /* Width */
2039     {
2040         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2041                                          "tools.calligraphic", "width", 15,
2042                                          NULL, tbl, TRUE, "altx-calligraphy",
2043                                          1, 100, 1.0, 10.0,
2044                                          sp_ddc_width_value_changed,  0.01, 0, 100);
2045         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2046     }
2048     /* Thinning */
2049     {
2050         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)"),
2051                                          "tools.calligraphic", "thinning", 0.1,
2052                                          NULL, tbl, FALSE, NULL,
2053                                          -1.0, 1.0, 0.01, 0.1,
2054                                          sp_ddc_velthin_value_changed, 0.01, 2);
2055         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2056     }
2058     //  interval
2059     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2061     /* Angle */
2062     {
2063         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2064                                              "tools.calligraphic", "angle", 30,
2065                                              NULL, tbl, TRUE, "calligraphy-angle",
2066                                              -90.0, 90.0, 1.0, 10.0,
2067                                              sp_ddc_angle_value_changed, 1, 0);
2068         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
2069     }
2071     /* Fixation */
2072     {
2073         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
2074                                          "tools.calligraphic", "flatness", 0.9,
2075                                          NULL, tbl, FALSE, NULL,
2076                                          0.0, 1.0, 0.01, 0.1,
2077                                          sp_ddc_flatness_value_changed, 0.01, 2);
2078         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2079     }
2081     //  interval
2082     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2084     /* Tremor */
2085     {
2086         GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
2087                                          "tools.calligraphic", "tremor", 0.0,
2088                                          NULL, tbl, FALSE, NULL,
2089                                          0.0, 1.0, 0.01, 0.1,
2090                                          sp_ddc_tremor_value_changed, 0.01, 2);
2091         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2092     }
2093     /* Mass */
2094     {
2095         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
2096                                          "tools.calligraphic", "mass", 0.02,
2097                                          NULL, tbl, FALSE, NULL,
2098                                          0.0, 1.0, 0.01, 0.1,
2099                                          sp_ddc_mass_value_changed, 0.01, 2);
2100         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2101     }
2103     /* Drag */
2104     {
2105         // TRANSLATORS: "drag" means "resistance" here
2106         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2107                                          "tools.calligraphic", "drag", 1,
2108                                          NULL, tbl, FALSE, NULL,
2109                                          0.0, 1.0, 0.01, 0.1,
2110                                          sp_ddc_drag_value_changed, 0.01, 2);
2111         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2112     }
2114     //  interval
2115     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2117     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2118     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2120     /* Use Pressure button */
2121     {
2122     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2123                                                  SP_BUTTON_TYPE_TOGGLE,
2124                                                  NULL,
2125                                                  "use_pressure",
2126                                                  _("Use the pressure of the input device to alter the width of the pen"),
2127                                                  tt);
2128     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2129     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2130     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2131     }
2133     /* Use Tilt button */
2134     {
2135     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2136                                                  SP_BUTTON_TYPE_TOGGLE,
2137                                                  NULL,
2138                                                  "use_tilt",
2139                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2140                                                  tt);
2141     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2142     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2143     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2144     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2145     }
2147     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2148     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2150     /* Reset */
2151     {
2152         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2153         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2154         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2155         gtk_widget_show(b);
2156         gtk_container_add(GTK_CONTAINER(hb), b);
2157         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2158         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2159     }
2162     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2163     swatch->setWatchedTool ("tools.calligraphic", true);
2164     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2165     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2167     gtk_widget_show_all(tbl);
2168     sp_set_font_size_smaller (tbl);
2170     return tbl;
2174 //########################
2175 //##    Circle / Arc    ##
2176 //########################
2178 static void 
2179 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2181     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2182     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2184     if (v1 == 0 && v2 == 0) {
2185         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2186             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2187             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2188         }
2189     } else {
2190         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2191         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2192     }
2195 static void
2196 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2198     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2200     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2201         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2202     }
2204     // quit if run by the attr_changed listener
2205     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2206         return;
2207     }
2209     // in turn, prevent listener from responding
2210     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2212     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2214     bool modmade = false;
2215     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2216          items != NULL;
2217          items = items->next)
2218     {
2219         SPItem *item = SP_ITEM(items->data);
2221         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2223             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2224             SPArc *arc = SP_ARC(item);
2226             if (!strcmp(value_name, "start"))
2227                 ge->start = (adj->value * M_PI)/ 180;
2228             else
2229                 ge->end = (adj->value * M_PI)/ 180;
2231             sp_genericellipse_normalize(ge);
2232             ((SPObject *)arc)->updateRepr();
2233             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2235             modmade = true;
2236         }
2237     }
2239     g_free(namespaced_name);
2241     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2243     sp_arctb_sensitivize (tbl, adj->value, other->value);
2245     if (modmade) {
2246         sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC, 
2247                                /* TODO: annotate */ "toolbox.cpp:2247");
2248     }
2250     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2251     spinbutton_defocus(GTK_OBJECT(tbl));
2253     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2257 static void
2258 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2260     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2263 static void
2264 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2266     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2269 static void
2270 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2272     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2274     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2275         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2276             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2277         } else {
2278             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2279         }
2280     }
2282     // quit if run by the attr_changed listener
2283     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2284         return;
2285     }
2287     // in turn, prevent listener from responding
2288     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2290     bool modmade = false;
2292     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2293         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2294              items != NULL;
2295              items = items->next)
2296         {
2297             if (SP_IS_ARC((SPItem *) items->data)) {
2298                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2299                 repr->setAttribute("sodipodi:open", "true");
2300                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2301                 modmade = true;
2302             }
2303         }
2304     } else {
2305         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2306              items != NULL;
2307              items = items->next)
2308         {
2309             if (SP_IS_ARC((SPItem *) items->data))    {
2310                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2311                 repr->setAttribute("sodipodi:open", NULL);
2312                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2313                 modmade = true;
2314             }
2315         }
2316     }
2318     if (modmade) {
2319         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC, 
2320                          /* TODO: annotate */ "toolbox.cpp:2320");
2321     }
2323     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2325     spinbutton_defocus(GTK_OBJECT(tbl));
2328 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2330     GtkWidget *tbl = GTK_WIDGET(obj);
2332     GtkAdjustment *adj;
2333     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2334     gtk_adjustment_set_value(adj, 0.0);
2335     gtk_adjustment_value_changed(adj);
2337     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2338     gtk_adjustment_set_value(adj, 0.0);
2339     gtk_adjustment_value_changed(adj);
2341     spinbutton_defocus(GTK_OBJECT(tbl));
2344 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2345                                       gchar const *old_value, gchar const *new_value,
2346                                       bool is_interactive, gpointer data)
2348     GtkWidget *tbl = GTK_WIDGET(data);
2350     // quit if run by the _changed callbacks
2351     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2352         return;
2353     }
2355     // in turn, prevent callbacks from responding
2356     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2358     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2359     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2361     GtkAdjustment *adj1,*adj2;
2362     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2363     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2364     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2365     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2367     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2369     char const *openstr = NULL;
2370     openstr = repr->attribute("sodipodi:open");
2371     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2373     if (openstr) {
2374         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2375     } else {
2376         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2377     }
2379     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2382 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2383     NULL, /* child_added */
2384     NULL, /* child_removed */
2385     arc_tb_event_attr_changed,
2386     NULL, /* content_changed */
2387     NULL  /* order_changed */
2388 };
2391 static void
2392 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2394     int n_selected = 0;
2395     Inkscape::XML::Node *repr = NULL;
2396     Inkscape::XML::Node *oldrepr = NULL;
2398     for (GSList const *items = selection->itemList();
2399          items != NULL;
2400          items = items->next)
2401     {
2402         if (SP_IS_ARC((SPItem *) items->data)) {
2403             n_selected++;
2404             repr = SP_OBJECT_REPR((SPItem *) items->data);
2405         }
2406     }
2408     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2410     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2411     if (n_selected == 0) {
2412         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2413     } else if (n_selected == 1) {
2414         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2415         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2417         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2419         if (oldrepr) { // remove old listener
2420             sp_repr_remove_listener_by_data(oldrepr, tbl);
2421             Inkscape::GC::release(oldrepr);
2422             oldrepr = 0;
2423             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2424         }
2426         if (repr) {
2427             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2428             Inkscape::GC::anchor(repr);
2429             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2430             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2431         }
2432     } else {
2433         // FIXME: implement averaging of all parameters for multiple selected
2434         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2435         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2436         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2437     }
2441 static GtkWidget *
2442 sp_arc_toolbox_new(SPDesktop *desktop)
2444     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2446     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2447     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2449     GtkTooltips *tt = gtk_tooltips_new();
2451     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2453     /* Start */
2454     {
2455         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2456                                          "tools.shapes.arc", "start", 0.0,
2457                                          NULL, tbl, TRUE, "altx-arc",
2458                                          -360.0, 360.0, 1.0, 10.0,
2459                                          sp_arctb_start_value_changed);
2460         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2461     }
2463     /* End */
2464     {
2465         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2466                                          "tools.shapes.arc", "end", 0.0,
2467                                          NULL, tbl, FALSE, NULL,
2468                                          -360.0, 360.0, 1.0, 10.0,
2469                                          sp_arctb_end_value_changed);
2470         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2471     }
2473     /* Segments / Pie checkbox */
2474     {
2475         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2476         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2477         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2479         gchar const *openstr = NULL;
2480         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2481         if (!openstr || (openstr && !strcmp(openstr, "false")))
2482             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2483         else
2484             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2486         gtk_widget_show(fscb);
2487         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2488         gtk_container_add(GTK_CONTAINER(hb), fscb);
2489         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2490         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2491     }
2493     /* Make Whole */
2494     {
2495         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2496         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2497         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2498         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2499         gtk_widget_show(b);
2500         gtk_container_add(GTK_CONTAINER(hb), b);
2501         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2502         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2503     }
2505     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2506     // sensitivize make whole and open checkbox
2507     {
2508         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2509         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2510         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2511     }
2513     sigc::connection *connection = new sigc::connection(
2514         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2515         );
2516     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2518     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL);
2519     swatch->setWatchedTool ("tools.shapes.arc", true);
2520     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2521     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2523     gtk_widget_show_all(tbl);
2524     sp_set_font_size_smaller (tbl);
2526     return tbl;
2532 // toggle button callbacks and updaters
2534 //########################
2535 //##      Dropper       ##
2536 //########################
2538 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2539     prefs_set_int_attribute ("tools.dropper", "pick", 
2540         // 0 and 1 are backwards here because of pref
2541         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2545 /**
2546  * Copy the current saved desktop color to the clipboard as full hex + alpha
2547  * color representation. This is useful for passing values between various 
2548  * input boxes, or directly to xml.
2549  */
2550 /* static void
2551 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2553     GtkWidget *tbl = GTK_WIDGET(obj);
2554     
2555     SPDesktop *desktop = 
2556         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2558    
2559     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2560 }*/
2563 /**
2564  * Copies currently saved desktop color to the clipboard as a hex value. This 
2565  * is useful for editing webpages and needing a value quickly for web
2566  * colors.
2567  * 
2568  * TODO: When the toggle of the dropper is set to not mix color against 
2569  *       page background, this still just gets the color of the page and 
2570  *       doesn't get the actual mixed against background which is needed 
2571  *       for the hex value ppl. want for web pages, etc.
2572  */
2574 /* static void
2575 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2577     GtkWidget *tbl = GTK_WIDGET(obj);
2578     
2579     SPDesktop *desktop = 
2580         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2581     
2582     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2583 }*/
2586 /**
2587  * Sets the input boxes with the changed color and opacity. This is used as a 
2588  * callback for style changing.
2589  */
2590 /* static bool
2591 sp_style_changed (const SPCSSAttr *css, gpointer data)
2593     // GrDrag *drag = (GrDrag *) data;
2594     
2595     // set fill of text entry box
2596     if (css->attribute("fill"))
2597         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2598             css->attribute("fill")); 
2600     // set opacity of text entry box
2601     if (css->attribute("fill-opacity"))
2602         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2603             css->attribute("fill-opacity")); 
2604     
2605     // set fill of text entry box
2606     if (css->attribute("stroke"))
2607         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2608             css->attribute("stroke")); 
2610     // set opacity of text entry box
2611     if (css->attribute("stroke-opacity"))
2612         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2613             css->attribute("stroke-opacity"));
2614     return false;
2617 */
2620 /**
2621  * Dropper auxiliary toolbar construction and setup.
2622  *
2623  * TODO: Would like to add swatch of current color.
2624  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2625  *       can drag and drop places. Will provide a nice mixing palette.
2626  */
2627 static GtkWidget *
2628 sp_dropper_toolbox_new(SPDesktop *desktop)
2630     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2632     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2633     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2635     GtkTooltips *tt = gtk_tooltips_new();
2637     
2638     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2639                        AUX_BETWEEN_BUTTON_GROUPS);
2640     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2643     
2644     /* RGB Input Field */
2645  /*   {
2646         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2647         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2648         gtk_widget_show (dropper_rgba_label);
2649         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2650         
2651         dropper_rgb_entry = gtk_entry_new ();
2652         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2653         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2654         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2655         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2656                          _("Hexidecimal representation of last selected "
2657                            "color"), 
2658                          NULL);
2659         gtk_widget_show (dropper_rgb_entry);
2660         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2661         
2662         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2663                            AUX_BETWEEN_BUTTON_GROUPS);
2664     } */
2665     
2666     /* Opacity Input Field */
2667 /*    {
2668         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2669         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2670         gtk_widget_show (dropper_opacity_label);
2671         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2672         
2673         dropper_opacity_entry = gtk_entry_new ();
2674         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2675         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2676         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2677         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2678                          _("Opacity of last selected color"), 
2679                          NULL);
2680         gtk_widget_show (dropper_opacity_entry);
2681         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2682         
2683         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2684                            AUX_BETWEEN_BUTTON_GROUPS);
2685     } */
2686     
2687     
2688     /* Copy to Clipboard */
2689 /*    {
2690         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2691         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2692         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2693                                       "RGB + Alpha (RGBA) to "
2694                                       "clipboard"), 
2695                              NULL);
2696         gtk_widget_show(b);
2697         gtk_container_add(GTK_CONTAINER(hb), b);
2698         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2699             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2700         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2701                            AUX_BETWEEN_BUTTON_GROUPS);
2702     } */
2705     /* Copy to Clipboard as HEX */
2706 /*    {
2707         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2708         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2709         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2710                                       "hexidecimal RGB without alpha " 
2711                                       "to clipboard"), NULL);
2712         gtk_widget_show(b);
2713         gtk_container_add(GTK_CONTAINER(hb), b);
2714         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2715             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2716         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2717                            AUX_BETWEEN_BUTTON_GROUPS);
2718     } */
2719     
2720     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2721     
2722     {
2723         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2724         
2725         GtkWidget *button = 
2726             sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2727                                      SP_BUTTON_TYPE_TOGGLE,
2728                                      NULL,
2729                                      "pick_color",
2730                                      _("When pressed, picks visible color "
2731                                        "without alpha and when not pressed, "
2732                                        "picks color including its "
2733                                        "alpha"),
2734                                      tt);
2736         gtk_widget_show(button);
2737         gtk_container_add (GTK_CONTAINER (hb), button);
2739         g_signal_connect_after (G_OBJECT (button), "clicked", 
2740                                 G_CALLBACK (toggle_dropper_color_pick), NULL);
2741         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2742                                       !prefs_get_int_attribute ("tools.dropper", 
2743                                                                "pick", 0));
2744         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2745                    AUX_BETWEEN_BUTTON_GROUPS);
2746     }
2747    
2748     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2749     
2751     // where new gtkmm stuff should go
2752     
2753     gtk_widget_show_all(tbl);
2754     sp_set_font_size_smaller (tbl);
2756     /*
2757     sigc::connection *connection = new sigc::connection(
2758         desktop->connectSetStyle(
2759             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2760                        desktop)) ); 
2761     
2762     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2763                      connection); */
2764     
2765     return tbl;
2769 //########################
2770 //##    Text Toolbox    ##
2771 //########################
2772 /*
2773 static void
2774 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2776     //Call back for letter sizing spinbutton
2779 static void
2780 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2782     //Call back for line height spinbutton
2785 static void
2786 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2788     //Call back for horizontal kerning spinbutton
2791 static void
2792 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2794     //Call back for vertical kerning spinbutton
2797 static void
2798 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2800     //Call back for letter rotation spinbutton
2801 }*/
2803 namespace {
2805 bool visible = false;
2807 void
2808 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
2811     SPStyle *query =
2812         sp_style_new ();
2814     int result_family =
2815         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY); 
2817     int result_style =
2818         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE); 
2820     int result_numbers =
2821         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
2823     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
2825     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
2826     if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
2827     {
2828         Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
2830         if (repr)
2831         {
2832             sp_style_read_from_repr (query, repr);
2833         }
2834         else
2835         {
2836             return;
2837         }
2838     }
2840     if (query->text)
2841     {
2842         if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
2843             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
2844             gtk_entry_set_text (GTK_ENTRY (entry), "");
2846         } else if (query->text->font_family.value) {
2848             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
2849             gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
2851             Gtk::TreePath path;
2852             try {
2853                 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
2854             } catch (...) {
2855                 return;
2856             }
2858             GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
2859             GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
2861             g_object_set_data (G_OBJECT (tselection), "block", gpointer(1)); 
2863             gtk_tree_selection_select_path (tselection, path.gobj());
2864             gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
2866             g_object_set_data (G_OBJECT (tselection), "block", gpointer(0)); 
2867         }
2869         //Size
2870         GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
2871         char *str = g_strdup_printf ("%.5g", query->font_size.computed);
2872         g_object_set_data (tbl, "size-block", gpointer(1)); 
2873         gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
2874         g_object_set_data (tbl, "size-block", gpointer(0)); 
2875         free (str);
2877         //Anchor
2878         if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
2879         {
2880             GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
2881             g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2882             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2883             g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2884         }
2885         else
2886         {
2887             if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
2888             {
2889                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
2890                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2891                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2892                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2893             }
2894             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
2895             {
2896                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
2897                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2898                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2899                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2900             }
2901             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
2902             {
2903                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
2904                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2905                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2906                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2907             }
2908         }
2910         //Style
2911         {
2912             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
2914             gboolean active = gtk_toggle_button_get_active (button);
2915             gboolean check  = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700); 
2917             if (active != check) 
2918             {
2919                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2920                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2921                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2922             }
2923         }
2925         {
2926             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
2928             gboolean active = gtk_toggle_button_get_active (button);
2929             gboolean check  = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL); 
2931             if (active != check)
2932             {
2933                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2934                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check); 
2935                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2936             }
2937         }
2939         //Orientation
2940         //locking both buttons, changing one affect all group (both)
2941         GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
2942         g_object_set_data (G_OBJECT (button), "block", gpointer(1));
2943         
2944         GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
2945         g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
2946         
2947         if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
2948         {
2949             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2950         }
2951         else
2952         {
2953             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
2954         }
2955         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
2956         g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
2957     }
2960 void
2961 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl) 
2963     sp_text_toolbox_selection_changed (selection, tbl); 
2966 void
2967 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
2969     sp_text_toolbox_selection_changed (NULL, tbl); 
2972 void
2973 sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
2974                                 GObject             *tbl) 
2976     SPDesktop    *desktop = SP_ACTIVE_DESKTOP;
2977     GtkTreeModel *model = 0;
2978     GtkWidget    *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
2979     GtkWidget    *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
2980     GtkTreeIter   iter;
2981     char         *family = 0;
2983     gdk_pointer_ungrab (GDK_CURRENT_TIME);
2984     gdk_keyboard_ungrab (GDK_CURRENT_TIME);
2986     if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
2987         return;
2988     }
2990     gtk_tree_model_get (model, &iter, 0, &family, -1);
2992     if (g_object_get_data (G_OBJECT (selection), "block"))
2993     {
2994         gtk_entry_set_text (GTK_ENTRY (entry), family);
2995         return;
2996     }
2997         
2998     gtk_widget_hide (popdown);
2999     visible = false;
3001     gtk_entry_set_text (GTK_ENTRY (entry), family);
3003     SPStyle *query =
3004         sp_style_new ();
3006     int result_numbers =
3007         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3009     SPCSSAttr *css = sp_repr_css_attr_new (); 
3010     sp_repr_css_set_property (css, "font-family", family); 
3012     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3013     if (result_numbers == QUERY_STYLE_NOTHING)
3014     {
3015         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3016         sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3017     }
3018     else
3019     {
3020         sp_desktop_set_style (desktop, css, true, true);
3021     }
3023     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3024                       /* TODO: annotate */ "toolbox.cpp:3024");
3025     sp_repr_css_attr_unref (css);
3026     free (family);
3027     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
3029     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3032 void
3033 sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
3034                                        GObject      *tbl) 
3036     const char *family = gtk_entry_get_text (entry);
3038     try {    
3039         Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3040         GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3041         GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3042         gtk_tree_selection_select_path (selection, path.gobj());
3043         gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3044         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));        
3045     } catch (...) {
3046         if (family && strlen (family))
3047         {
3048             gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3049         }
3050     }
3053 void
3054 sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
3055                                    gpointer          data)
3057     if (g_object_get_data (G_OBJECT (button), "block")) return;
3058     if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3059     int prop = GPOINTER_TO_INT(data); 
3061     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3062     SPCSSAttr *css = sp_repr_css_attr_new (); 
3064     switch (prop)
3065     {
3066         case 0:
3067         {
3068             sp_repr_css_set_property (css, "text-anchor", "start"); 
3069             sp_repr_css_set_property (css, "text-align", "start"); 
3070             break;
3071         }
3072         case 1:
3073         {
3074             sp_repr_css_set_property (css, "text-anchor", "middle"); 
3075             sp_repr_css_set_property (css, "text-align", "center"); 
3076             break;
3077         }
3079         case 2:
3080         {
3081             sp_repr_css_set_property (css, "text-anchor", "end"); 
3082             sp_repr_css_set_property (css, "text-align", "end"); 
3083             break;
3084         }
3086         case 3:
3087         {
3088             sp_repr_css_set_property (css, "text-anchor", "start"); 
3089             sp_repr_css_set_property (css, "text-align", "justify"); 
3090             break;
3091         }
3092     }
3094     SPStyle *query =
3095         sp_style_new ();
3096     int result_numbers =
3097         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3099     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3100     if (result_numbers == QUERY_STYLE_NOTHING)
3101     {
3102         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3103     }
3105     sp_desktop_set_style (desktop, css, true, true);
3106     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3107                       /* TODO: annotate */ "toolbox.cpp:3107");
3108     sp_repr_css_attr_unref (css);
3110     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3113 void
3114 sp_text_toolbox_style_toggled (GtkToggleButton  *button,
3115                                gpointer          data)
3117     if (g_object_get_data (G_OBJECT (button), "block")) return;
3119     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3120     SPCSSAttr   *css        = sp_repr_css_attr_new (); 
3121     int          prop       = GPOINTER_TO_INT(data); 
3122     bool         active     = gtk_toggle_button_get_active (button);
3125     switch (prop)
3126     {
3127         case 0:
3128         {
3129             sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" ); 
3130             break;
3131         }
3133         case 1:
3134         {
3135             sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal"); 
3136             break;
3137         }
3138     }
3140     SPStyle *query =
3141         sp_style_new ();
3142     int result_numbers =
3143         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3145     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3146     if (result_numbers == QUERY_STYLE_NOTHING)
3147     {
3148         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3149     }
3151     sp_desktop_set_style (desktop, css, true, true);
3152     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3153                       /* TODO: annotate */ "toolbox.cpp:3153");
3154     sp_repr_css_attr_unref (css);
3156     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3159 void
3160 sp_text_toolbox_orientation_toggled (GtkRadioButton  *button,
3161                                      gpointer         data)
3163     if (g_object_get_data (G_OBJECT (button), "block")) {
3164         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3165         return;
3166     }
3167     
3168     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3169     SPCSSAttr   *css        = sp_repr_css_attr_new (); 
3170     int          prop       = GPOINTER_TO_INT(data); 
3172     switch (prop)
3173     {
3174         case 0:
3175         {
3176             sp_repr_css_set_property (css, "writing-mode", "lr");
3177             break;
3178         }
3180         case 1:
3181         {
3182             sp_repr_css_set_property (css, "writing-mode", "tb"); 
3183             break;
3184         }
3185     }
3187     SPStyle *query =
3188         sp_style_new ();
3189     int result_numbers =
3190         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3192     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3193     if (result_numbers == QUERY_STYLE_NOTHING)
3194     {
3195         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3196     }
3198     sp_desktop_set_style (desktop, css, true, true);
3199     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT, 
3200                       /* TODO: annotate */ "toolbox.cpp:3200");
3201     sp_repr_css_attr_unref (css);
3203     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3206 gboolean
3207 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3209     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3210     if (!desktop) return FALSE;
3212     switch (get_group0_keyval (event)) {
3213         case GDK_Escape: // defocus
3214             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3215             return TRUE; // I consumed the event
3216             break;
3217         case GDK_Return: // defocus
3218         case GDK_KP_Enter:
3219             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3220             return TRUE; // I consumed the event
3221             break;
3222     }
3223     return FALSE;
3226 gboolean
3227 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3229     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3230     if (!desktop) return FALSE;
3232     switch (get_group0_keyval (event)) {
3233         case GDK_Escape: // defocus
3234             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3235             sp_text_toolbox_selection_changed (NULL, tbl); // update
3236             return TRUE; // I consumed the event
3237             break;
3238     }
3239     return FALSE;
3242 gboolean
3243 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3245     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3246     if (!desktop) return FALSE;
3248     switch (get_group0_keyval (event)) {
3249         case GDK_Escape: // defocus
3250             gtk_widget_hide (w);
3251             visible = false;
3252             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3253             return TRUE; // I consumed the event
3254             break;
3255     }
3256     return FALSE;
3260 void
3261 sp_text_toolbox_size_changed  (GtkComboBox *cbox,
3262                                GObject     *tbl) 
3264     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3266     if (g_object_get_data (tbl, "size-block")) return;
3268 #if GTK_CHECK_VERSION(2,6,0)
3269     char *text = gtk_combo_box_get_active_text (cbox);
3270 #else // GTK_CHECK_VERSION(2,6,0)
3271     GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3272     GtkTreeIter iter;
3273     char *text = NULL;
3275     if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3276         gtk_tree_model_get (model, &iter, 0, &text, -1);
3277 #endif // GTK_CHECK_VERSION(2,6,0)
3279     SPCSSAttr *css = sp_repr_css_attr_new (); 
3280     sp_repr_css_set_property (css, "font-size", text); 
3281     free (text);
3283     SPStyle *query =
3284         sp_style_new ();
3285     int result_numbers =
3286         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS); 
3288     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3289     if (result_numbers == QUERY_STYLE_NOTHING)
3290     {
3291         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3292     }
3294     sp_desktop_set_style (desktop, css, true, true);
3295     sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE, 
3296                             /* TODO: annotate */ "toolbox.cpp:3296");
3297     sp_repr_css_attr_unref (css);
3300     if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3301         gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3304 void
3305 sp_text_toolbox_text_popdown_clicked    (GtkButton          *button,
3306                                          GObject            *tbl)
3308     GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3309     GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3310     int x, y;
3312     if (!visible)
3313     {
3314         gdk_window_get_origin (widget->window, &x, &y);
3315         gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space 
3316         gtk_widget_show_all (popdown);
3318         gdk_pointer_grab (widget->window, TRUE,
3319                           GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3320                                         GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3321                                         GDK_POINTER_MOTION_MASK),
3322                           NULL, NULL, GDK_CURRENT_TIME);
3324         gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3326         visible = true;
3327     }
3328     else
3329     {
3330         gdk_pointer_ungrab (GDK_CURRENT_TIME);
3331         gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3332         gtk_widget_hide (popdown);
3333         visible = false;
3334     }
3337 gboolean
3338 sp_text_toolbox_entry_focus_in  (GtkWidget        *entry,
3339                                  GdkEventFocus    *event,
3340                                  GObject          *tbl)
3342     gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3343     return FALSE;
3346 gboolean
3347 sp_text_toolbox_popdown_focus_out (GtkWidget        *popdown,
3348                                    GdkEventFocus    *event,
3349                                    GObject          *tbl)
3351     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3353     gtk_widget_hide (popdown);
3354     visible = false;
3355     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3356     return TRUE;
3359 void
3360 cell_data_func  (GtkTreeViewColumn *column,
3361                  GtkCellRenderer   *cell,
3362                  GtkTreeModel      *tree_model,
3363                  GtkTreeIter       *iter,
3364                  gpointer           data)
3366     char        *family,
3367         *family_escaped,
3368         *sample_escaped;
3370     static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3372     gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3374     family_escaped = g_markup_escape_text (family, -1);
3375     sample_escaped = g_markup_escape_text (sample, -1);
3376     
3377     std::stringstream markup; 
3378     markup << family_escaped << "  <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3379     g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3381     free (family);
3382     free (family_escaped);
3383     free (sample_escaped);
3386 GtkWidget*
3387 sp_text_toolbox_new (SPDesktop *desktop)
3389     GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
3391     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3392     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3394     GtkTooltips *tt = gtk_tooltips_new();
3395     Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3397     ////////////Family
3398     //Window
3399     GtkWidget   *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3400     gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3402     //Entry
3403     GtkWidget           *entry = gtk_entry_new ();
3404     gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3405     GtkEntryCompletion  *completion = gtk_entry_completion_new ();
3406     gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3407     gtk_entry_completion_set_text_column (completion, 0);
3408     gtk_entry_completion_set_minimum_key_length (completion, 1); 
3409     g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3410     gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3411     aux_toolbox_space (tbl, 1);
3412     gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3413         
3414     //Button
3415     GtkWidget   *button = gtk_button_new ();
3416     gtk_container_add       (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3417     gtk_box_pack_start      (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3419     //Popdown
3420     GtkWidget           *sw = gtk_scrolled_window_new (NULL, NULL);
3421     GtkWidget           *treeview = gtk_tree_view_new ();
3423     GtkCellRenderer     *cell = gtk_cell_renderer_text_new ();
3424     GtkTreeViewColumn   *column = gtk_tree_view_column_new ();
3425     gtk_tree_view_column_pack_start (column, cell, FALSE);
3426     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3427     gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3428     gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3430     gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3431     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3432 #if GTK_CHECK_VERSION(2,6,0)
3433     gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3434 #endif // GTK_CHECK_VERSION(2,6,0)
3436     //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3438     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); 
3439     gtk_container_add (GTK_CONTAINER (sw), treeview);
3441     gtk_container_add (GTK_CONTAINER (window), sw);
3442     gtk_widget_set_size_request (window, 300, 450);
3444     g_signal_connect (G_OBJECT (entry),  "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3445     g_signal_connect (G_OBJECT (entry),  "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3446     g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3448     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3450     g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3451     g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3453     GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3454     g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3456     g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3457     g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3458     g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3459     g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3460     g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3462     GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3463     aux_toolbox_space (tbl, 1);
3464     GtkWidget *box = gtk_event_box_new ();
3465     gtk_container_add (GTK_CONTAINER (box), image);
3466     gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3467     g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3468     GtkTooltips *tooltips = gtk_tooltips_new ();
3469     gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3470     gtk_widget_hide (GTK_WIDGET (box));
3471     g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3473     ////////////Size
3474     const char *sizes[] = {
3475         "4", "6", "8", "9", "10", "11", "12", "13", "14",
3476         "16", "18", "20", "22", "24", "28",
3477         "32", "36", "40", "48", "56", "64", "72", "144"
3478     };
3480     GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3481     for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3482     gtk_widget_set_size_request (cbox, 80, -1);
3483     aux_toolbox_space (tbl, 1);
3484     gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3485     g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3486     g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3487     gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3489     //spacer
3490     aux_toolbox_space (tbl, 4);
3491     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3493     ////////////Text anchor
3494     GtkWidget *group   = gtk_radio_button_new (NULL);
3495     GtkWidget *row     = gtk_hbox_new (FALSE, 4);
3496     g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3498     // left
3499     GtkWidget *rbutton = group;
3500     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3501     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3502     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3504     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3505     g_object_set_data   (G_OBJECT (tbl), "text-start", rbutton);
3506     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3507     gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3509     // center
3510     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3511     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3512     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3513     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3515     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3516     g_object_set_data   (G_OBJECT (tbl), "text-middle", rbutton);
3517     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1)); 
3518     gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3520     // right
3521     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3522     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3523     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3524     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3526     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3527     g_object_set_data   (G_OBJECT (tbl), "text-end", rbutton);
3528     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3529     gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3531     // fill
3532     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3533     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3534     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3535     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3537     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3538     g_object_set_data   (G_OBJECT (tbl), "text-fill", rbutton);
3539     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3540     gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3542     aux_toolbox_space (tbl, 1);
3543     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3545     //spacer
3546     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3548     ////////////Text style
3549     row = gtk_hbox_new (FALSE, 4);
3551     // bold 
3552     rbutton = gtk_toggle_button_new (); 
3553     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3554     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3555     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3556     gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3558     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3559     g_object_set_data   (G_OBJECT (tbl), "style-bold", rbutton);
3560     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3562     // italic
3563     rbutton = gtk_toggle_button_new (); 
3564     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3565     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3566     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3567     gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3569     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3570     g_object_set_data   (G_OBJECT (tbl), "style-italic", rbutton);
3571     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1)); 
3573     aux_toolbox_space (tbl, 1);
3574     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3576     //spacer
3577     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3579     ////////////Text orientation
3580     group   = gtk_radio_button_new (NULL);
3581     row     = gtk_hbox_new (FALSE, 4);
3582     g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3584     // horizontal
3585     rbutton = group;
3586     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3587     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR)); 
3588     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3589     gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3591     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3592     g_object_set_data   (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3593     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3595     // vertical
3596     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3597     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3598     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB)); 
3599     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3600     gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3602     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3603     g_object_set_data   (G_OBJECT (tbl), "orientation-vertical", rbutton);
3604     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1)); 
3605     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3608     //watch selection
3609     Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3611     sigc::connection *c_selection_changed =
3612         new sigc::connection (sp_desktop_selection (desktop)->connectChanged 
3613                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3614     pool->add_connection ("selection-changed", c_selection_changed);
3616     sigc::connection *c_selection_modified =
3617         new sigc::connection (sp_desktop_selection (desktop)->connectModified 
3618                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3619     pool->add_connection ("selection-modified", c_selection_modified);
3621     sigc::connection *c_subselection_changed =
3622         new sigc::connection (desktop->connectToolSubselectionChanged
3623                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3624     pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3626     Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3629 #if 0
3630     // horizontal
3631     {
3632         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3633         GtkWidget *b = group = gtk_radio_button_new (NULL);
3634         gtk_container_add (GTK_CONTAINER (b), px);
3635         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3636         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3637         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3638         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3639     }
3641     // vertical
3642     {
3643         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3644         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3645         gtk_container_add (GTK_CONTAINER (b), px);
3646         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3647         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3648         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3649         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3650     }
3652     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3654     // letter spacing
3655     {
3656         {
3657             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3658             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3659             gtk_container_add (GTK_CONTAINER (hb), image);
3660             gtk_widget_show(image);
3661             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3662         }
3663     
3664         {
3665             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3666                                              "tools.text", "letter_spacing", 0.0,
3667                                              us, tbl, FALSE, NULL,
3668                                              -1000.0, 1000.0, 0.1, 0.1,
3669                                              sp_text_letter_changed, 0.1, 1);
3670             gtk_widget_set_size_request (hb, 45, 6);
3671             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3672         }
3673     }
3675     // line spacing
3676     {
3677         {
3678             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3679             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3680             gtk_container_add (GTK_CONTAINER (hb), image);
3681             gtk_widget_show(image);
3682             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3683         }
3684     
3685         {
3686             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3687                                              "tools.text", "line_spacing", 0,
3688                                              us, tbl, FALSE, NULL,
3689                                              -1000.0, 1000.0, 0.1, 0.1,
3690                                              sp_text_line_changed, 0.1, 1);
3691             gtk_widget_set_size_request (hb, 45, 0);
3692             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3693         }
3694     }
3696     {
3697         // horizontal kerning/vertical kerning units menu: create
3698         GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3699         sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3700         sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3702         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3704         // horizontal kerning
3705         {
3706             {
3707                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3708                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3709                 gtk_container_add (GTK_CONTAINER (hb), image);
3710                 gtk_widget_show(image);
3711                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3712             }
3714             {
3715                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3716                                                  "tools.text", "horizontal_kerning", 0,
3717                                                  us, tbl, FALSE, NULL,
3718                                                  -100.00, 100.00, 0.01, 0.1,
3719                                                  sp_text_horiz_kern_changed);
3720                 gtk_widget_set_size_request (hb, 45, 0);
3721                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3722             }
3723         }
3725         // vertical kerning
3726         {
3727             {
3728                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3729                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3730                 gtk_container_add (GTK_CONTAINER (hb), image);
3731                 gtk_widget_show(image);
3732                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3733             }
3734     
3735             {
3736                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3737                                                  "tools.text", "vertical_kerning", 0,
3738                                                  us, tbl, FALSE, NULL,
3739                                                  -100.00, 100.00, 0.01, 0.1,
3740                                                  sp_text_vert_kern_changed);
3741                 gtk_widget_set_size_request (hb, 45, 0);
3742                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3743             }
3744         }
3746         // add the units menu
3747         gtk_widget_show(us);
3748         gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3749         gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3750     }
3752     // letter rotation
3753     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3754     {
3755         {
3756             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3757             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3758             gtk_container_add (GTK_CONTAINER (hb), image);
3759             gtk_widget_show(image);
3760             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3761         }
3762         {
3763             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3764                                              "tools.text", "letter_rotation", 0,
3765                                              us, tbl, FALSE, NULL,
3766                                              -180.0, 180.0, 0.1, 0.1,
3767                                              sp_text_letter_rotation_changed, 0.1, 1);
3768             gtk_widget_set_size_request (hb, 45, 0);
3769             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3770         }
3771         // rotation degree label
3772         {
3773             GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3774             gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3775         }
3776     }
3777         
3778     // Remove Manual Kerns
3779     {
3780         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3781         GtkWidget *button = gtk_button_new ();
3782         gtk_container_add (GTK_CONTAINER (button), px);
3783         gtk_widget_show(button);
3784         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
3785         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
3786         gtk_widget_set_sensitive(button, TRUE);
3787         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
3788     }
3789 #endif
3791     gtk_widget_show_all (tbl);
3792     return tbl;
3794 } // end of sp_text_toolbox_new()
3796 }//<unnamed> namespace
3799 //#########################
3800 //##  Connector Toolbox  ##
3801 //#########################
3803 static void sp_connector_path_set_avoid(void)
3805     cc_selection_set_avoid(true);
3809 static void sp_connector_path_set_ignore(void)
3811     cc_selection_set_avoid(false);
3815 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3817     // quit if run by the _changed callbacks
3818     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3819         return;
3820     }
3821         
3822     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3823             "desktop");
3824     SPDocument *doc = sp_desktop_document(desktop);
3826     if (!sp_document_get_undo_sensitive(doc))
3827     {
3828         return;
3829     }
3831     // in turn, prevent callbacks from responding
3832     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3833     
3834     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3835     
3836     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3837     SP_OBJECT(desktop->namedview)->updateRepr();
3838     
3839     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3840     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3841         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3842         NR::Matrix m = NR::identity();
3843         avoid_item_move(&m, item);
3844     }
3846     if (items) {
3847         g_slist_free(items);
3848     }
3849     
3850     sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR, 
3851                      /* TODO: annotate */ "toolbox.cpp:3851");
3853     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3854     
3855     spinbutton_defocus(GTK_OBJECT(tbl));
3859 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3860         gchar const *name, gchar const *old_value, gchar const *new_value,
3861         bool is_interactive, gpointer data)
3863     GtkWidget *tbl = GTK_WIDGET(data);
3865     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3866         return;
3867     }
3868     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3869         return;
3870     }
3872     GtkAdjustment *adj = (GtkAdjustment*)
3873             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3874     gdouble spacing = defaultConnSpacing;
3875     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3876     
3877     gtk_adjustment_set_value(adj, spacing);
3881 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3882     NULL, /* child_added */
3883     NULL, /* child_removed */
3884     connector_tb_event_attr_changed,
3885     NULL, /* content_changed */
3886     NULL  /* order_changed */
3887 };
3890 static GtkWidget *
3891 sp_connector_toolbox_new(SPDesktop *desktop)
3893     GtkTooltips *tt = gtk_tooltips_new();
3894     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3895     
3896     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3897     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3899     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3900             AUX_BETWEEN_BUTTON_GROUPS);
3902     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3903             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3904             tt, _("Make connectors avoid selected objects"));
3906     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
3907             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3908             tt, _("Make connectors ignore selected objects"));
3910     //  interval
3911     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3912             AUX_BETWEEN_BUTTON_GROUPS);
3914     // Spacing spinbox
3915     {
3916         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3917                 _("The amount of space left around objects by auto-routing connectors"),
3918                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3919                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3920                 connector_spacing_changed, 1, 0);
3922         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3923                 AUX_SPACING);
3924     }
3926     gtk_widget_show_all(tbl);
3927     sp_set_font_size_smaller (tbl);
3928     
3929     // Code to watch for changes to the connector-spacing attribute in
3930     // the XML.
3931     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3932     g_assert(repr != NULL);
3933         
3934     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3935             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3936     
3937     if (oldrepr) { // remove old listener
3938         sp_repr_remove_listener_by_data(oldrepr, tbl);
3939         Inkscape::GC::release(oldrepr);
3940         oldrepr = NULL;
3941         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3942     }
3944     if (repr) {
3945         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3946         Inkscape::GC::anchor(repr);
3947         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3948         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3949     }
3950     
3951     return tbl;
3953 } // end of sp_connector_toolbox_new()
3956 /*
3957   Local Variables:
3958   mode:c++
3959   c-file-style:"stroustrup"
3960   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3961   indent-tabs-mode:nil
3962   fill-column:99
3963   End:
3964 */
3965 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :