Code

5a57aa952158470d917c98a126736d9d676d5ed7
[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 <gtk/gtk.h>
33 #include "widgets/button.h"
34 #include "widgets/widget-sizes.h"
35 #include "widgets/spw-utilities.h"
36 #include "widgets/spinbutton-events.h"
38 #include "prefs-utils.h"
39 #include "verbs.h"
40 #include "sp-namedview.h"
41 #include "desktop.h"
42 #include "desktop-handles.h"
43 #include "nodepath.h"
44 #include "xml/repr.h"
45 #include "xml/node-event-vector.h"
46 #include <glibmm/i18n.h>
47 #include "helper/unit-menu.h"
48 #include "helper/units.h"
50 #include "inkscape.h"
51 #include "conn-avoid-ref.h"
54 #include "select-toolbar.h"
55 #include "gradient-toolbar.h"
57 #include "connector-context.h"
58 #include "sp-rect.h"
59 #include "sp-star.h"
60 #include "sp-spiral.h"
61 #include "sp-ellipse.h"
62 #include "selection.h"
63 #include "document-private.h"
65 #include "mod360.h"
67 #include "toolbox.h"
69 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
70 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
72 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
73 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
74 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
75 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
76 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
77 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
78 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
79 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
80 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
81 static GtkWidget *sp_text_toolbox_new(SPDesktop *desktop);
82 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
85 static struct {
86     gchar const *type_name;
87     gchar const *data_name;
88     sp_verb_t verb;
89     sp_verb_t doubleclick_verb;
90 } const tools[] = {
91     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
92     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
93     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
94     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
95     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
96     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
97     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
98     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
99     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
100     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
101     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
102     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
103     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
104     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
105     { NULL, NULL, 0, 0 }
106 };
108 static struct {
109     gchar const *type_name;
110     gchar const *data_name;
111     GtkWidget *(*create_func)(SPDesktop *desktop);
112 } const aux_toolboxes[] = {
113     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
114     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
115     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
116     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
117     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
118     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
119     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
120     { "SPPencilContext", "pencil_toolbox", NULL },
121     { "SPPenContext", "pen_toolbox", NULL },
122     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
123     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
124     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
125     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
126     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
127     { NULL, NULL, NULL }
128 };
130 static void toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
132 static void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
133 static void update_tool_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
134 static void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
135 static void update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
136 static void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop);
137 static void update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
139 /* Global text entry widgets necessary for update */
140 /* GtkWidget *dropper_rgb_entry, 
141           *dropper_opacity_entry ; */
142 // should be made a private member once this is converted to class
144 static void delete_connection(GObject *obj, sigc::connection *connection) {
145     connection->disconnect();
146     delete connection;
149 static GtkWidget *
150 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
151                       GtkTooltips *tt, gchar const *tip)
153     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
154     gtk_widget_show(b);
155     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
156     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
158     return b;
162 GtkWidget *
163 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
164                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
165                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
167     SPAction *action = verb->get_action(view);
168     if (!action) return NULL;
170     SPAction *doubleclick_action;
171     if (doubleclick_verb)
172         doubleclick_action = doubleclick_verb->get_action(view);
173     else
174         doubleclick_action = NULL;
176     /* fixme: Handle sensitive/unsensitive */
177     /* fixme: Implement sp_button_new_from_action */
178     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
179     gtk_widget_show(b);
180     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
182     return b;
185 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
186                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
188     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
191 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
192                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
194     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
197 GtkWidget *
198 sp_tool_toolbox_new()
200     GtkTooltips *tt = gtk_tooltips_new();
201     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
203     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
204     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
206     gtk_widget_set_sensitive(tb, FALSE);
208     GtkWidget *hb = gtk_handle_box_new();
209     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
210     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
211     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
213     gtk_container_add(GTK_CONTAINER(hb), tb);
214     gtk_widget_show(GTK_WIDGET(tb));
216     sigc::connection* conn = new sigc::connection;
217     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
219     return hb;
222 static void
223 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
225     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
226     gtk_widget_queue_resize(child);
229 static void
230 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
232     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
233     gtk_widget_queue_resize(child);
236 GtkWidget *
237 sp_aux_toolbox_new()
239     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
241     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
242     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
243     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
244     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
245     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
247     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
248     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
250     gtk_widget_set_sensitive(tb, FALSE);
252     GtkWidget *hb = gtk_handle_box_new();
253     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
254     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
255     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
257     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
258     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
260     gtk_container_add(GTK_CONTAINER(hb), tb);
261     gtk_widget_show(GTK_WIDGET(tb));
263     sigc::connection* conn = new sigc::connection;
264     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
266     return hb;
269 //####################################
270 //# Commands Bar
271 //####################################
273 GtkWidget *
274 sp_commands_toolbox_new()
276     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
278     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
279     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
280     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
281     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
282     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
284     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
285     gtk_widget_set_sensitive(tb, FALSE);
287     GtkWidget *hb = gtk_handle_box_new();
288     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
289     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
290     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
292     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
293     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
295     gtk_container_add(GTK_CONTAINER(hb), tb);
296     gtk_widget_show(GTK_WIDGET(tb));
298     sigc::connection* conn = new sigc::connection;
299     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
301     return hb;
305 //####################################
306 //# node editing callbacks
307 //####################################
309 void
310 sp_node_path_edit_add(void)
312     sp_node_selected_add_node();
315 void
316 sp_node_path_edit_delete(void)
318     sp_node_selected_delete();
321 void
322 sp_node_path_edit_delete_segment(void)
324     sp_node_selected_delete_segment();
327 void
328 sp_node_path_edit_break(void)
330     sp_node_selected_break();
333 void
334 sp_node_path_edit_join(void)
336     sp_node_selected_join();
339 void
340 sp_node_path_edit_join_segment(void)
342     sp_node_selected_join_segment();
345 void
346 sp_node_path_edit_toline(void)
348     sp_node_selected_set_line_type(NR_LINETO);
351 void
352 sp_node_path_edit_tocurve(void)
354     sp_node_selected_set_line_type(NR_CURVETO);
357 void
358 sp_node_path_edit_cusp(void)
360     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
363 void
364 sp_node_path_edit_smooth(void)
366     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
369 void
370 sp_node_path_edit_symmetrical(void)
372     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
377 //################################
378 //##    Node Editing Toolbox    ##
379 //################################
381 static GtkWidget *
382 sp_node_toolbox_new(SPDesktop *desktop)
384     Inkscape::UI::View::View *view = desktop;
386     GtkTooltips *tt = gtk_tooltips_new();
387     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
389     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
391     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
392         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
393     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
394         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
396     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
398     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
399         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
400     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
401         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
403     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
404         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
406     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
407         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
409     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
411     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
412         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
414     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
415         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
417     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
418         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
420     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
422     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
423         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
425     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
426         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
428     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
430     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
432     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
434     gtk_widget_show_all(tb);
436     return tb;
438 } // end of sp_node_toolbox_new()
441 //########################
442 //##    Zoom Toolbox    ##
443 //########################
445 static GtkWidget *
446 sp_zoom_toolbox_new(SPDesktop *desktop)
448     Inkscape::UI::View::View *view=desktop;
450     GtkTooltips *tt = gtk_tooltips_new();
451     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
453     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
454                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
456     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);
458     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);
460     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
462     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);
464     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);
466     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);
468     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);
470     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
472     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);
474     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);
476     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
478     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);
480     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);
482     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);
484     gtk_widget_show_all(tb);
486     return tb;
488 } // end of sp_zoom_toolbox_new()
490 void
491 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
493     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")));
497 void
498 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
500     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")));
503 void
504 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
506     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")));
510 static void
511 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
513     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
514     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
516     if (old_desktop) {
517         GList *children, *iter;
519         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
520         for ( iter = children ; iter ; iter = iter->next ) {
521             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
522         }
523         g_list_free(children);
524     }
526     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
528     if (desktop) {
529         gtk_widget_set_sensitive(toolbox, TRUE);
530         setup_func(toolbox, desktop);
531         update_func(desktop, desktop->event_context, toolbox);
532         *conn = desktop->connectEventContextChanged 
533             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
534     } else {
535         gtk_widget_set_sensitive(toolbox, FALSE);
536     }
538 } // end of toolbox_set_desktop()
541 static void
542 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
544     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
545     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
546     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
548     for (int i = 0 ; tools[i].type_name ; i++ ) {
549         GtkWidget *button =
550             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
551                                                               SP_BUTTON_TYPE_TOGGLE,
552                                                               Inkscape::Verb::get(tools[i].verb),
553                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
554                                                               desktop,
555                                                               tooltips );
557         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
558                            (gpointer)button );
559     }
563 static void
564 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
566     gchar const *const tname = ( eventcontext
567                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
568                                  : NULL );
569     for (int i = 0 ; tools[i].type_name ; i++ ) {
570         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
571         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
572     }
575 static void
576 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
578     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
580     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
581         GtkWidget *sub_toolbox;
582         if (aux_toolboxes[i].create_func == NULL)
583             sub_toolbox = sp_empty_toolbox_new(desktop);
584         else
585             sub_toolbox = aux_toolboxes[i].create_func(desktop);
587         gtk_size_group_add_widget( grouper, sub_toolbox );
589         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
590         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
591     }
592     g_object_unref( G_OBJECT(grouper) );
595 static void
596 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
598     gchar const *tname = ( eventcontext
599                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
600                            : NULL );
601     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
602         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
603         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
604             gtk_widget_show_all(sub_toolbox);
605             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
606         } else {
607             gtk_widget_hide(sub_toolbox);
608         }
609     }
612 static void
613 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
615     Inkscape::UI::View::View *view = desktop;
617     GtkTooltips *tt = gtk_tooltips_new();
618     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
620     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
621     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
623     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_NEW), view, tt);
624     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_OPEN), view, tt);
625     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_SAVE), view, tt);
626     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_PRINT), view, tt);
628     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
630     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_IMPORT), view, tt);
631     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_FILE_EXPORT), view, tt);
633     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
635     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNDO), view, tt);
636     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_REDO), view, tt);
638     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
640     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_COPY), view, tt);
641     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CUT), view, tt);
642     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_PASTE), view, tt);
644     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
646     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
647     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
648     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
650     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
652     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_DUPLICATE), view, tt);
653     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_CLONE), view, tt);
654     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNLINK_CLONE), view, tt);
656     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
658     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_GROUP), view, tt);
659     sp_toolbox_button_normal_new_from_verb(tb, toolboxSize, Inkscape::Verb::get(SP_VERB_SELECTION_UNGROUP), view, tt);
661     // disabled until we have icons for them:
663     //find
665     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_TILE), view, tt);
666     //sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_EDIT_UNTILE), view, tt);
668     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
670     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_FILL_STROKE), view, tt);
671     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_TEXT), view, tt);
672     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_XML_EDITOR), view, tt);
673     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_ALIGN_DISTRIBUTE), 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_DIALOG_DISPLAY), view, tt);
678     sp_toolbox_button_new_from_verb(tb, toolboxSize, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_DIALOG_NAMEDVIEW), view, tt);
680     gtk_widget_show_all(tb);
682     gtk_container_add(GTK_CONTAINER(toolbox), tb);
685 static void
686 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
690 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
692     gtk_widget_show(toolbox_toplevel);
693     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
695     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
696     if (!shown_toolbox) {
697         return;
698     }
699     gtk_widget_show(toolbox);
701     // need to show the spacer, or the padding will be off
702     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
703     gtk_widget_show(spacer);
705     gtk_widget_show_all(shown_toolbox);
708 void
709 aux_toolbox_space(GtkWidget *tb, gint space)
711     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
714 static GtkWidget *
715 sp_empty_toolbox_new(SPDesktop *desktop)
717     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
718     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
719     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
721     gtk_widget_show_all(tbl);
722     sp_set_font_size_smaller (tbl);
724     return tbl;
727 // helper UI functions
729 GtkWidget *
730 sp_tb_spinbutton(
731     gchar *label, gchar const *tooltip,
732     gchar const *path, gchar const *data, gdouble def,
733     GtkWidget *us,
734     GtkWidget *tbl,
735     gboolean altx, gchar const *altx_mark,
736     gdouble lower, gdouble upper, gdouble step, gdouble page,
737     void (*callback)(GtkAdjustment *, GtkWidget *),
738     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
740     GtkTooltips *tt = gtk_tooltips_new();
742     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
744     GtkWidget *l = gtk_label_new(label);
745     gtk_widget_show(l);
746     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
747     gtk_container_add(GTK_CONTAINER(hb), l);
749     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
750                                       lower, upper, step, page, page);
751     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
752     if (us)
753         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
755     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
756     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
757     if (altx)
758         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
759     gtk_widget_set_size_request(sb, 
760                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
761                                 AUX_SPINBUTTON_HEIGHT);
762     gtk_widget_show(sb);
763     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
764     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
765     gtk_container_add(GTK_CONTAINER(hb), sb);
766     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
768     return hb;
771 #define MODE_LABEL_WIDTH 70
773 //########################
774 //##       Star         ##
775 //########################
777 static void
778 sp_stb_magnitude_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
780     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
782     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
783         // do not remember prefs if this call is initiated by an undo change, because undoing object
784         // creation sets bogus values to its attributes before it is deleted
785         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
786     }
788     // quit if run by the attr_changed listener
789     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
790         return;
791     }
793     // in turn, prevent listener from responding
794     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
796     bool modmade = false;
798     Inkscape::Selection *selection = sp_desktop_selection(desktop);
799     GSList const *items = selection->itemList();
800     for (; items != NULL; items = items->next) {
801         if (SP_IS_STAR((SPItem *) items->data)) {
802             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
803             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
804             sp_repr_set_svg_double(repr, "sodipodi:arg2",
805                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
806                                     + M_PI / (gint)adj->value));
807             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
808             modmade = true;
809         }
810     }
811     if (modmade)  sp_document_done(sp_desktop_document(desktop));
813     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
815     spinbutton_defocus(GTK_OBJECT(tbl));
818 static void
819 sp_stb_proportion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
821     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
823     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
824         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
825     }
827     // quit if run by the attr_changed listener
828     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
829         return;
830     }
832     // in turn, prevent listener from responding
833     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
835     bool modmade = false;
836     Inkscape::Selection *selection = sp_desktop_selection(desktop);
837     GSList const *items = selection->itemList();
838     for (; items != NULL; items = items->next) {
839         if (SP_IS_STAR((SPItem *) items->data)) {
840             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
842             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
843             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
844             if (r2 < r1) {
845                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
846             } else {
847                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
848             }
850             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
851             modmade = true;
852         }
853     }
855     if (modmade) sp_document_done(sp_desktop_document(desktop));
857     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
859     spinbutton_defocus(GTK_OBJECT(tbl));
862 static void
863 sp_stb_sides_flat_state_changed(GtkWidget *widget, GtkObject *tbl)
865     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
867     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
868         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
869             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "true");
870         } else {
871             prefs_set_string_attribute("tools.shapes.star", "isflatsided", "false");
872         }
873     }
875     // quit if run by the attr_changed listener
876     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
877         return;
878     }
880     // in turn, prevent listener from responding
881     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
883     Inkscape::Selection *selection = sp_desktop_selection(desktop);
884     GSList const *items = selection->itemList();
885     GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
886     bool modmade = false;
887     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
888         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
889         for (; items != NULL; items = items->next) {
890             if (SP_IS_STAR((SPItem *) items->data)) {
891                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
892                 repr->setAttribute("inkscape:flatsided", "true");
893                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
894                 modmade = true;
895             }
896         }
897     } else {
898         gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
899         for (; items != NULL; items = items->next) {
900             if (SP_IS_STAR((SPItem *) items->data)) {
901                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
902                 repr->setAttribute("inkscape:flatsided", "false");
903                 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
904                 modmade = true;
905             }
906         }
907     }
908     if (modmade) sp_document_done(sp_desktop_document(desktop));
910     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
912     spinbutton_defocus(GTK_OBJECT(tbl));
915 static void
916 sp_stb_rounded_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
918     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
920     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
921         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
922     }
924     // quit if run by the attr_changed listener
925     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
926         return;
927     }
929     // in turn, prevent listener from responding
930     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
932     bool modmade = false;
934     Inkscape::Selection *selection = sp_desktop_selection(desktop);
935     GSList const *items = selection->itemList();
936     for (; items != NULL; items = items->next) {
937         if (SP_IS_STAR((SPItem *) items->data)) {
938             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
939             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
940             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
941             modmade = true;
942         }
943     }
944     if (modmade)  sp_document_done(sp_desktop_document(desktop));
946     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
948     spinbutton_defocus(GTK_OBJECT(tbl));
952 static void
953 sp_stb_randomized_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
955     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
957     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
958         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
959     }
961     // quit if run by the attr_changed listener
962     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
963         return;
964     }
966     // in turn, prevent listener from responding
967     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
969     bool modmade = false;
971     Inkscape::Selection *selection = sp_desktop_selection(desktop);
972     GSList const *items = selection->itemList();
973     for (; items != NULL; items = items->next) {
974         if (SP_IS_STAR((SPItem *) items->data)) {
975             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
976             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
977             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
978             modmade = true;
979         }
980     }
981     if (modmade)  sp_document_done(sp_desktop_document(desktop));
983     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
985     spinbutton_defocus(GTK_OBJECT(tbl));
989 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
990                                        gchar const *old_value, gchar const *new_value,
991                                        bool is_interactive, gpointer data)
993     GtkWidget *tbl = GTK_WIDGET(data);
995     // quit if run by the _changed callbacks
996     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
997         return;
998     }
1000     // in turn, prevent callbacks from responding
1001     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1003     GtkAdjustment *adj;
1005     if (!strcmp(name, "inkscape:randomized")) {
1006         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1007         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1008     } else if (!strcmp(name, "inkscape:rounded")) {
1009         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1010         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1011     } else if (!strcmp(name, "inkscape:flatsided")) {
1012         GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1013         GtkWidget *prop_widget = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1014         char const *flatsides = repr->attribute("inkscape:flatsided");
1015         if (flatsides && !strcmp(flatsides,"false" )) {
1016             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1017             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), TRUE);
1018         } else {
1019             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1020             gtk_widget_set_sensitive(GTK_WIDGET(prop_widget), FALSE);
1021         }
1022     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1023         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1024         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1025         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1026         if (r2 < r1) {
1027             gtk_adjustment_set_value(adj, r2/r1);
1028         } else {
1029             gtk_adjustment_set_value(adj, r1/r2);
1030         }
1031     } else if (!strcmp(name, "sodipodi:sides")) {
1032         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1033         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1034     }
1036     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1040 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1042     NULL, /* child_added */
1043     NULL, /* child_removed */
1044     star_tb_event_attr_changed,
1045     NULL, /* content_changed */
1046     NULL  /* order_changed */
1047 };
1050 /**
1051  *  \param selection Should not be NULL.
1052  */
1053 static void
1054 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1056     int n_selected = 0;
1057     Inkscape::XML::Node *repr = NULL;
1058     Inkscape::XML::Node *oldrepr = NULL;
1060     for (GSList const *items = selection->itemList();
1061          items != NULL;
1062          items = items->next)
1063     {
1064         if (SP_IS_STAR((SPItem *) items->data)) {
1065             n_selected++;
1066             repr = SP_OBJECT_REPR((SPItem *) items->data);
1067         }
1068     }
1070     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1072     if (n_selected == 0) {
1073         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1074     } else if (n_selected == 1) {
1075         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1077         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1078         if (oldrepr) { // remove old listener
1079             sp_repr_remove_listener_by_data(oldrepr, tbl);
1080             Inkscape::GC::release(oldrepr);
1081             oldrepr = 0;
1082             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1083         }
1085         if (repr) {
1086             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1087             Inkscape::GC::anchor(repr);
1088             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1089             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1090         }
1091     } else {
1092         // FIXME: implement averaging of all parameters for multiple selected stars
1093         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1094         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1095     }
1099 static void
1100 sp_stb_defaults(GtkWidget *widget, GtkWidget *tbl)
1102     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1103     // callbacks to lump all the changes for all selected objects in one undo step
1105     GtkAdjustment *adj;
1107     // fixme: make settable in prefs!
1108     gint mag = 5;
1109     gdouble prop = 0.5;
1110     gboolean flat = FALSE;
1111     gdouble randomized = 0;
1112     gdouble rounded = 0;
1114     GtkWidget *fscb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "flat_checkbox");
1115     gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  flat);
1116     GtkWidget *sb2 = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "prop_widget");
1117     gtk_widget_set_sensitive(GTK_WIDGET(sb2), !flat);
1119     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1120     gtk_adjustment_set_value(adj, mag);
1121     gtk_adjustment_value_changed(adj);
1123     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1124     gtk_adjustment_set_value(adj, prop);
1125     gtk_adjustment_value_changed(adj);
1127     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rounded");
1128     gtk_adjustment_set_value(adj, rounded);
1129     gtk_adjustment_value_changed(adj);
1131     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "randomized");
1132     gtk_adjustment_set_value(adj, randomized);
1133     gtk_adjustment_value_changed(adj);
1135     spinbutton_defocus(GTK_OBJECT(tbl));
1139 void
1140 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1142     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1143     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1144     GtkWidget *l = gtk_label_new(NULL);
1145     gtk_label_set_markup(GTK_LABEL(l), title);
1146     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1147     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1148     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1152 static GtkWidget *
1153 sp_star_toolbox_new(SPDesktop *desktop)
1155     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1157     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1158     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1160     GtkTooltips *tt = gtk_tooltips_new();
1162     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1164     gchar const *flatsidedstr = NULL;
1166     /* Flatsided checkbox */
1167     {
1168         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1169         GtkWidget *fscb = gtk_check_button_new_with_label(_("Polygon"));
1170         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
1171         flatsidedstr = prefs_get_string_attribute("tools.shapes.star", "isflatsided");
1172         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1173             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
1174         else
1175             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
1176         gtk_tooltips_set_tip(tt, fscb, _("Regular polygon (with one handle) instead of a star"), NULL);
1177         gtk_widget_show(fscb);
1178         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
1179         gtk_container_add(GTK_CONTAINER(hb), fscb);
1180         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_stb_sides_flat_state_changed ), tbl);
1181         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1182     }
1184     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
1186     /* Magnitude */
1187     {
1188         GtkWidget *hb = sp_tb_spinbutton(_("Corners:"), _("Number of corners of a polygon or star"),
1189                                          "tools.shapes.star", "magnitude", 3,
1190                                          NULL, tbl, TRUE, "altx-star",
1191                                          3, 1024, 1, 1,
1192                                          sp_stb_magnitude_value_changed, 1, 0);
1193         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1194     }
1196     /* Spoke ratio */
1197     {
1198         GtkWidget *hb = sp_tb_spinbutton(_("Spoke ratio:"),
1199                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1200                                          // Base radius is the same for the closest handle.
1201                                          _("Base radius to tip radius ratio"),
1202                                          "tools.shapes.star", "proportion", 0.5,
1203                                          NULL, tbl, FALSE, NULL,
1204                                          0.01, 1.0, 0.01, 0.1,
1205                                          sp_stb_proportion_value_changed);
1206         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1207         g_object_set_data(G_OBJECT(tbl), "prop_widget", hb);
1208         if (!flatsidedstr || (flatsidedstr && !strcmp(flatsidedstr, "false")))
1209             gtk_widget_set_sensitive(GTK_WIDGET(hb), TRUE);
1210         else
1211             gtk_widget_set_sensitive(GTK_WIDGET(hb), FALSE);
1212     }
1214     /* Roundedness */
1215     {
1216         GtkWidget *hb = sp_tb_spinbutton(_("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1217                                          "tools.shapes.star", "rounded", 0.0,
1218                                          NULL, tbl, FALSE, NULL,
1219                                          -100.0, 100.0, 0.01, 0.1,
1220                                          sp_stb_rounded_value_changed);
1221         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1222     }
1224     /* Randomization */
1225     {
1226         GtkWidget *hb = sp_tb_spinbutton(_("Randomized:"), _("Scatter randomly the corners and angles"),
1227                                          "tools.shapes.star", "randomized", 0.0,
1228                                          NULL, tbl, FALSE, NULL,
1229                                          -10.0, 10.0, 0.001, 0.01,
1230                                          sp_stb_randomized_value_changed, 0.1, 3);
1231         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1232     }
1234     aux_toolbox_space(tbl, AUX_SPACING);
1236     /* Reset */
1237     {
1238         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1239         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1240         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1241         gtk_widget_show(b);
1242         gtk_container_add(GTK_CONTAINER(hb), b);
1243         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_stb_defaults), tbl);
1244         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
1245     }
1247     gtk_widget_show_all(tbl);
1248     sp_set_font_size_smaller (tbl);
1250     sigc::connection *connection = new sigc::connection(
1251         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)tbl))
1252         );
1253     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1255     return tbl;
1259 //########################
1260 //##       Rect         ##
1261 //########################
1263 static void 
1264 sp_rtb_sensitivize (GtkWidget *tbl)
1266     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1267     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1268     GtkWidget *not_rounded = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "not_rounded");
1270     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1271         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), FALSE);
1272     } else {
1273         gtk_widget_set_sensitive(GTK_WIDGET(not_rounded), TRUE);
1274     }
1278 static void
1279 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1280                           void (*setter)(SPRect *, gdouble))
1282     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1284     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1285     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1287     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1288         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1289     }
1291     // quit if run by the attr_changed listener
1292     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1293         return;
1294     }
1296     // in turn, prevent listener from responding
1297     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1299     bool modmade = false;
1300     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1301     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1302         if (SP_IS_RECT(items->data)) {
1303             if (adj->value != 0) {
1304                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1305             } else {
1306                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1307             }
1308             modmade = true;
1309         }
1310     }
1312     sp_rtb_sensitivize (tbl);
1314     if (modmade) {
1315         sp_document_done(sp_desktop_document(desktop));
1316     }
1318     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1320     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1321     spinbutton_defocus(GTK_OBJECT(tbl));
1324 static void
1325 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1327     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1330 static void
1331 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1333     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1336 static void
1337 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1339     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1342 static void
1343 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1345     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1350 static void
1351 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1353     GtkWidget *tbl = GTK_WIDGET(obj);
1355     GtkAdjustment *adj;
1357     adj = (GtkAdjustment*)gtk_object_get_data(obj, "rx");
1358     gtk_adjustment_set_value(adj, 0.0);
1359     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1360     gtk_adjustment_value_changed(adj);
1362     adj = (GtkAdjustment*)gtk_object_get_data(obj, "ry");
1363     gtk_adjustment_set_value(adj, 0.0);
1364     gtk_adjustment_value_changed(adj);
1366     sp_rtb_sensitivize (tbl);
1368     spinbutton_defocus(GTK_OBJECT(tbl));
1371 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1372                                        gchar const *old_value, gchar const *new_value,
1373                                        bool is_interactive, gpointer data)
1375     GtkWidget *tbl = GTK_WIDGET(data);
1377     // quit if run by the _changed callbacks
1378     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1379         return;
1380     }
1382     // in turn, prevent callbacks from responding
1383     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1385     GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
1386     SPUnit const *unit = sp_unit_selector_get_unit(SP_UNIT_SELECTOR(us));
1388     SPItem *item = SP_ITEM(g_object_get_data(G_OBJECT(tbl), "item"));
1389     if (SP_IS_RECT(item)) {
1390         {
1391             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1392             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1393             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1394         }
1396         {
1397             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1398             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1399             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1400         }
1402         {
1403             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1404             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1405             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1406         }
1408         {
1409             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1410             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1411             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1412         }
1413     }
1415     sp_rtb_sensitivize (tbl);
1417     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1421 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1422     NULL, /* child_added */
1423     NULL, /* child_removed */
1424     rect_tb_event_attr_changed,
1425     NULL, /* content_changed */
1426     NULL  /* order_changed */
1427 };
1429 /**
1430  *  \param selection should not be NULL.
1431  */
1432 static void
1433 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1435     int n_selected = 0;
1436     Inkscape::XML::Node *repr = NULL;
1437     SPItem *item = NULL;
1438     Inkscape::XML::Node *oldrepr = NULL;
1440     for (GSList const *items = selection->itemList();
1441          items != NULL;
1442          items = items->next) {
1443         if (SP_IS_RECT((SPItem *) items->data)) {
1444             n_selected++;
1445             item = (SPItem *) items->data;
1446             repr = SP_OBJECT_REPR(item);
1447         }
1448     }
1450     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1452     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1454     if (n_selected == 0) {
1455         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1457         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1458         gtk_widget_set_sensitive(w, FALSE);
1459         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1460         gtk_widget_set_sensitive(h, FALSE);
1462     } else if (n_selected == 1) {
1463         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1464         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1466         GtkWidget *w = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "width_sb");
1467         gtk_widget_set_sensitive(w, TRUE);
1468         GtkWidget *h = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(tbl), "height_sb");
1469         gtk_widget_set_sensitive(h, TRUE);
1471         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1472         if (oldrepr) { // remove old listener
1473             sp_repr_remove_listener_by_data(oldrepr, tbl);
1474             Inkscape::GC::release(oldrepr);
1475             oldrepr = 0;
1476             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1477         }
1478         if (repr) {
1479             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1480             g_object_set_data(G_OBJECT(tbl), "item", item);
1481             Inkscape::GC::anchor(repr);
1482             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1483             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1484         }
1485     } else {
1486         // FIXME: implement averaging of all parameters for multiple selected
1487         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1488         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1489         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1490     }
1494 static GtkWidget *
1495 sp_rect_toolbox_new(SPDesktop *desktop)
1497     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1499     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1500     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1502     GtkTooltips *tt = gtk_tooltips_new();
1504     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1506     // rx/ry units menu: create
1507     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
1508     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
1509     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
1510     // fixme: add % meaning per cent of the width/height
1512     /* W */
1513     {
1514         GtkWidget *hb = sp_tb_spinbutton(_("W:"), _("Width of rectangle"),
1515                                          "tools.shapes.rect", "width", 0,
1516                                          us, tbl, TRUE, "altx-rect",
1517                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1518                                          sp_rtb_width_value_changed);
1519         gtk_object_set_data(GTK_OBJECT(tbl), "width_sb", hb);
1520         gtk_widget_set_sensitive(hb, FALSE);
1521         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1522     }
1524     /* H */
1525     {
1526         GtkWidget *hb = sp_tb_spinbutton(_("H:"), _("Height of rectangle"),
1527                                          "tools.shapes.rect", "height", 0,
1528                                          us, tbl, FALSE, NULL,
1529                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1530                                          sp_rtb_height_value_changed);
1531         gtk_object_set_data(GTK_OBJECT(tbl), "height_sb", hb);
1532         gtk_widget_set_sensitive(hb, FALSE);
1533         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1534     }
1536     /* rx */
1537     {
1538         GtkWidget *hb = sp_tb_spinbutton(_("Rx:"), _("Horizontal radius of rounded corners"),
1539                                          "tools.shapes.rect", "rx", 0,
1540                                          us, tbl, FALSE, NULL,
1541                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1542                                          sp_rtb_rx_value_changed);
1543         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1544     }
1546     /* ry */
1547     {
1548         GtkWidget *hb = sp_tb_spinbutton(_("Ry:"), _("Vertical radius of rounded corners"),
1549                                          "tools.shapes.rect", "ry", 0,
1550                                          us, tbl, FALSE, NULL,
1551                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1552                                          sp_rtb_ry_value_changed);
1553         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1554     }
1556     // add the units menu
1557     gtk_widget_show(us);
1558     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1559     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
1561     /* Reset */
1562     {
1563         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1564         GtkWidget *b = gtk_button_new_with_label(_("Not rounded"));
1565         gtk_object_set_data(GTK_OBJECT(tbl), "not_rounded", b);
1566         gtk_tooltips_set_tip(tt, b, _("Make corners sharp"), NULL);
1567         gtk_widget_show(b);
1568         gtk_container_add(GTK_CONTAINER(hb), b);
1569         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_rtb_defaults), tbl);
1570         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1571     }
1573     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1574     sp_rtb_sensitivize (tbl);
1576     gtk_widget_show_all(tbl);
1577     sp_set_font_size_smaller (tbl);
1579     sigc::connection *connection = new sigc::connection(
1580         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)tbl))
1581         );
1582     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1584     return tbl;
1587 //########################
1588 //##       Spiral       ##
1589 //########################
1591 static void
1592 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1594     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1596     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1597         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1598     }
1600     // quit if run by the attr_changed listener
1601     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1602         return;
1603     }
1605     // in turn, prevent listener from responding
1606     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1608     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1610     bool modmade = false;
1611     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1612          items != NULL;
1613          items = items->next)
1614     {
1615         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1616             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1617             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1618             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1619             modmade = true;
1620         }
1621     }
1623     g_free(namespaced_name);
1625     if (modmade) {
1626         sp_document_done(sp_desktop_document(desktop));
1627     }
1629     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1631     spinbutton_defocus(GTK_OBJECT(tbl));
1634 static void
1635 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1637     sp_spl_tb_value_changed(adj, tbl, "revolution");
1640 static void
1641 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1643     sp_spl_tb_value_changed(adj, tbl, "expansion");
1646 static void
1647 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1649     sp_spl_tb_value_changed(adj, tbl, "t0");
1652 static void
1653 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1655     GtkWidget *tbl = GTK_WIDGET(obj);
1657     GtkAdjustment *adj;
1659     // fixme: make settable
1660     gdouble rev = 5;
1661     gdouble exp = 1.0;
1662     gdouble t0 = 0.0;
1664     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1665     gtk_adjustment_set_value(adj, rev);
1666     gtk_adjustment_value_changed(adj);
1668     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1669     gtk_adjustment_set_value(adj, exp);
1670     gtk_adjustment_value_changed(adj);
1672     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1673     gtk_adjustment_set_value(adj, t0);
1674     gtk_adjustment_value_changed(adj);
1676     spinbutton_defocus(GTK_OBJECT(tbl));
1680 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1681                                          gchar const *old_value, gchar const *new_value,
1682                                          bool is_interactive, gpointer data)
1684     GtkWidget *tbl = GTK_WIDGET(data);
1686     // quit if run by the _changed callbacks
1687     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1688         return;
1689     }
1691     // in turn, prevent callbacks from responding
1692     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1694     GtkAdjustment *adj;
1695     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
1696     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
1698     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
1699     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
1701     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
1702     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
1704     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1708 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
1709     NULL, /* child_added */
1710     NULL, /* child_removed */
1711     spiral_tb_event_attr_changed,
1712     NULL, /* content_changed */
1713     NULL  /* order_changed */
1714 };
1716 static void
1717 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1719     int n_selected = 0;
1720     Inkscape::XML::Node *repr = NULL;
1721     Inkscape::XML::Node *oldrepr = NULL;
1723     for (GSList const *items = selection->itemList();
1724          items != NULL;
1725          items = items->next)
1726     {
1727         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1728             n_selected++;
1729             repr = SP_OBJECT_REPR((SPItem *) items->data);
1730         }
1731     }
1733     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
1735     if (n_selected == 0) {
1736         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
1737     } else if (n_selected == 1) {
1738         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1740         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1741         if (oldrepr) { // remove old listener
1742             sp_repr_remove_listener_by_data(oldrepr, tbl);
1743             Inkscape::GC::release(oldrepr);
1744             oldrepr = 0;
1745             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1746         }
1748         if (repr) {
1749             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1750             Inkscape::GC::anchor(repr);
1751             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
1752             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
1753         }
1754     } else {
1755         // FIXME: implement averaging of all parameters for multiple selected
1756         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1757         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1758     }
1762 static GtkWidget *
1763 sp_spiral_toolbox_new(SPDesktop *desktop)
1765     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1766     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1767     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1769     GtkTooltips *tt = gtk_tooltips_new();
1771     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
1773     /* Revolution */
1774     {
1775         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
1776                                          "tools.shapes.spiral", "revolution", 3.0,
1777                                          NULL, tbl, TRUE, "altx-spiral",
1778                                          0.01, 1024.0, 0.1, 1.0,
1779                                          sp_spl_tb_revolution_value_changed, 1, 2);
1780         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1781     }
1783     /* Expansion */
1784     {
1785         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
1786                                          "tools.shapes.spiral", "expansion", 1.0,
1787                                          NULL, tbl, FALSE, NULL,
1788                                          0.0, 1000.0, 0.01, 1.0,
1789                                          sp_spl_tb_expansion_value_changed);
1790         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1791     }
1793     /* T0 */
1794     {
1795         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
1796                                          "tools.shapes.spiral", "t0", 0.0,
1797                                          NULL, tbl, FALSE, NULL,
1798                                          0.0, 0.999, 0.01, 1.0,
1799                                          sp_spl_tb_t0_value_changed);
1800         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1801     }
1803     aux_toolbox_space(tbl, AUX_SPACING);
1805     /* Reset */
1806     {
1807         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1808         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
1809         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
1810         gtk_widget_show(b);
1811         gtk_container_add(GTK_CONTAINER(hb), b);
1812         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
1813         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1814     }
1816     gtk_widget_show_all(tbl);
1817     sp_set_font_size_smaller (tbl);
1819     sigc::connection *connection = new sigc::connection(
1820         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
1821         );
1822     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
1824     return tbl;
1828 //########################
1829 //##     Calligraphy    ##
1830 //########################
1832 static void
1833 sp_ddc_mass_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1835     prefs_set_double_attribute("tools.calligraphic", "mass", adj->value);
1836     spinbutton_defocus(GTK_OBJECT(tbl));
1839 static void
1840 sp_ddc_drag_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1842     prefs_set_double_attribute("tools.calligraphic", "drag", adj->value);
1843     spinbutton_defocus(GTK_OBJECT(tbl));
1846 static void
1847 sp_ddc_angle_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1849     prefs_set_double_attribute("tools.calligraphic", "angle", adj->value);
1850     spinbutton_defocus(GTK_OBJECT(tbl));
1853 static void
1854 sp_ddc_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1856     prefs_set_double_attribute("tools.calligraphic", "width", adj->value * 0.01);
1857     spinbutton_defocus(GTK_OBJECT(tbl));
1860 static void
1861 sp_ddc_velthin_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1863     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
1864     spinbutton_defocus(GTK_OBJECT(tbl));
1867 static void
1868 sp_ddc_flatness_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1870     prefs_set_double_attribute("tools.calligraphic", "flatness", adj->value);
1871     spinbutton_defocus(GTK_OBJECT(tbl));
1874 static void
1875 sp_ddc_tremor_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1877     prefs_set_double_attribute("tools.calligraphic", "tremor", adj->value);
1878     spinbutton_defocus(GTK_OBJECT(tbl));
1881 static void
1882 sp_ddc_pressure_state_changed(GtkWidget *button, gpointer data)
1884     prefs_set_int_attribute ("tools.calligraphic", "usepressure", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1887 static void
1888 sp_ddc_tilt_state_changed(GtkWidget *button, GtkWidget *calligraphy_angle)
1890     prefs_set_int_attribute ("tools.calligraphic", "usetilt", gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
1892     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1895 static void sp_ddc_defaults(GtkWidget *, GtkWidget *tbl)
1897     // FIXME: make defaults settable via Inkscape Options
1898     struct KeyValue {
1899         char const *key;
1900         double value;
1901     } const key_values[] = {
1902         {"mass", 0.02},
1903         {"drag", 1.0},
1904         {"angle", 30.0},
1905         {"width", 15},
1906         {"thinning", 0.1},
1907         {"tremor", 0.0},
1908         {"flatness", 0.9}
1909     };
1911     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
1912         KeyValue const &kv = key_values[i];
1913         GtkAdjustment &adj = *static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(tbl), kv.key));
1914         gtk_adjustment_set_value(&adj, kv.value);
1915     }
1917     spinbutton_defocus(GTK_OBJECT(tbl));
1920 static GtkWidget *
1921 sp_calligraphy_toolbox_new(SPDesktop *desktop)
1923     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1924     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1925     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1927     GtkTooltips *tt = gtk_tooltips_new();
1928     GtkWidget *calligraphy_angle;
1930     //  interval
1931     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1933     /* Width */
1934     {
1935         GtkWidget *hb = sp_tb_spinbutton(_("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
1936                                          "tools.calligraphic", "width", 15,
1937                                          NULL, tbl, TRUE, "altx-calligraphy",
1938                                          1, 100, 1.0, 10.0,
1939                                          sp_ddc_width_value_changed,  0.01, 0, 100);
1940         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1941     }
1943     /* Thinning */
1944     {
1945         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)"),
1946                                          "tools.calligraphic", "thinning", 0.1,
1947                                          NULL, tbl, FALSE, NULL,
1948                                          -1.0, 1.0, 0.01, 0.1,
1949                                          sp_ddc_velthin_value_changed, 0.01, 2);
1950         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1951     }
1953     //  interval
1954     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1956     /* Angle */
1957     {
1958         calligraphy_angle = sp_tb_spinbutton(_("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
1959                                              "tools.calligraphic", "angle", 30,
1960                                              NULL, tbl, TRUE, "calligraphy-angle",
1961                                              -90.0, 90.0, 1.0, 10.0,
1962                                              sp_ddc_angle_value_changed, 1, 0);
1963         gtk_box_pack_start(GTK_BOX(tbl), calligraphy_angle, FALSE, FALSE, AUX_SPACING);
1964     }
1966     /* Fixation */
1967     {
1968         GtkWidget *hb = sp_tb_spinbutton(_("Fixation:"), _("How fixed is the pen angle (0 = always perpendicular to stroke direction, 1 = fixed)"),
1969                                          "tools.calligraphic", "flatness", 0.9,
1970                                          NULL, tbl, FALSE, NULL,
1971                                          0.0, 1.0, 0.01, 0.1,
1972                                          sp_ddc_flatness_value_changed, 0.01, 2);
1973         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1974     }
1976     //  interval
1977     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
1979     /* Tremor */
1980     {
1981         GtkWidget *hb = sp_tb_spinbutton(_("Tremor:"), _("How uneven or trembling is the pen stroke"),
1982                                          "tools.calligraphic", "tremor", 0.0,
1983                                          NULL, tbl, FALSE, NULL,
1984                                          0.0, 1.0, 0.01, 0.1,
1985                                          sp_ddc_tremor_value_changed, 0.01, 2);
1986         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1987     }
1988     /* Mass */
1989     {
1990         GtkWidget *hb = sp_tb_spinbutton(_("Mass:"), _("How much inertia affects the movement of the pen"),
1991                                          "tools.calligraphic", "mass", 0.02,
1992                                          NULL, tbl, FALSE, NULL,
1993                                          0.0, 1.0, 0.01, 0.1,
1994                                          sp_ddc_mass_value_changed, 0.01, 2);
1995         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
1996     }
1998     /* Drag */
1999     {
2000         // TRANSLATORS: "drag" means "resistance" here
2001         GtkWidget *hb = sp_tb_spinbutton(_("Drag:"), _("How much resistance affects the movement of the pen"),
2002                                          "tools.calligraphic", "drag", 1,
2003                                          NULL, tbl, FALSE, NULL,
2004                                          0.0, 1.0, 0.01, 0.1,
2005                                          sp_ddc_drag_value_changed, 0.01, 2);
2006         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2007     }
2009     //  interval
2010     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2012     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
2013     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
2015     /* Use Pressure button */
2016     {
2017     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2018                                                  SP_BUTTON_TYPE_TOGGLE,
2019                                                  NULL,
2020                                                  "use_pressure",
2021                                                  _("Use the pressure of the input device to alter the width of the pen"),
2022                                                  tt);
2023     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_pressure_state_changed), NULL);
2024     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usepressure", 1));
2025     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2026     }
2028     /* Use Tilt button */
2029     {
2030     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2031                                                  SP_BUTTON_TYPE_TOGGLE,
2032                                                  NULL,
2033                                                  "use_tilt",
2034                                                  _("Use the tilt of the input device to alter the angle of the pen's nib"),
2035                                                  tt);
2036     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (sp_ddc_tilt_state_changed), calligraphy_angle);
2037     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.calligraphic", "usetilt", 1));
2038     gtk_widget_set_sensitive(GTK_WIDGET(calligraphy_angle), !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
2039     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
2040     }
2042     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
2043     gtk_box_pack_start(GTK_BOX(tbl), cvbox, FALSE, FALSE, 0);
2045     /* Reset */
2046     {
2047         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2048         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2049         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2050         gtk_widget_show(b);
2051         gtk_container_add(GTK_CONTAINER(hb), b);
2052         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_ddc_defaults), tbl);
2053         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2054     }
2056 /*
2057      // Tablet features
2058     {
2059         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2060         GtkWidget *fscb = gtk_check_button_new_with_label(_("Tablet"));
2061         gtk_widget_set_sensitive(GTK_WIDGET(fscb), TRUE);
2066         gtk_tooltips_set_tip(tt, fscb, _("Enable/Disable drawing tablet features"), NULL);
2067         gtk_widget_show(fscb);
2068         gtk_object_set_data(GTK_OBJECT(tbl), "flat_checkbox", fscb);
2069         gtk_container_add(GTK_CONTAINER(hb), fscb);
2071         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_SPACING);
2072     }
2073 */
2075     gtk_widget_show_all(tbl);
2076     sp_set_font_size_smaller (tbl);
2078     return tbl;
2082 //########################
2083 //##    Circle / Arc    ##
2084 //########################
2086 static void 
2087 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2089     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2090     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2092     if (v1 == 0 && v2 == 0) {
2093         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2094             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2095             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2096         }
2097     } else {
2098         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2099         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2100     }
2103 static void
2104 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2106     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2108     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2109         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2110     }
2112     // quit if run by the attr_changed listener
2113     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2114         return;
2115     }
2117     // in turn, prevent listener from responding
2118     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2120     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2122     bool modmade = false;
2123     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2124          items != NULL;
2125          items = items->next)
2126     {
2127         SPItem *item = SP_ITEM(items->data);
2129         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2131             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2132             SPArc *arc = SP_ARC(item);
2134             if (!strcmp(value_name, "start"))
2135                 ge->start = (adj->value * M_PI)/ 180;
2136             else
2137                 ge->end = (adj->value * M_PI)/ 180;
2139             sp_genericellipse_normalize(ge);
2140             ((SPObject *)arc)->updateRepr();
2141             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2143             modmade = true;
2144         }
2145     }
2147     g_free(namespaced_name);
2149     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2151     sp_arctb_sensitivize (tbl, adj->value, other->value);
2153     if (modmade) {
2154         sp_document_maybe_done(sp_desktop_document(desktop), value_name);
2155     }
2157     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2158     spinbutton_defocus(GTK_OBJECT(tbl));
2160     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2164 static void
2165 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2167     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2170 static void
2171 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2173     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2176 static void
2177 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2179     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2181     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2182         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2183             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2184         } else {
2185             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2186         }
2187     }
2189     // quit if run by the attr_changed listener
2190     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2191         return;
2192     }
2194     // in turn, prevent listener from responding
2195     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2197     bool modmade = false;
2199     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2200         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2201              items != NULL;
2202              items = items->next)
2203         {
2204             if (SP_IS_ARC((SPItem *) items->data)) {
2205                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2206                 repr->setAttribute("sodipodi:open", "true");
2207                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2208                 modmade = true;
2209             }
2210         }
2211     } else {
2212         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2213              items != NULL;
2214              items = items->next)
2215         {
2216             if (SP_IS_ARC((SPItem *) items->data))    {
2217                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2218                 repr->setAttribute("sodipodi:open", NULL);
2219                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2220                 modmade = true;
2221             }
2222         }
2223     }
2225     if (modmade) {
2226         sp_document_done(sp_desktop_document(desktop));
2227     }
2229     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2231     spinbutton_defocus(GTK_OBJECT(tbl));
2234 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2236     GtkWidget *tbl = GTK_WIDGET(obj);
2238     GtkAdjustment *adj;
2239     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2240     gtk_adjustment_set_value(adj, 0.0);
2241     gtk_adjustment_value_changed(adj);
2243     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2244     gtk_adjustment_set_value(adj, 0.0);
2245     gtk_adjustment_value_changed(adj);
2247     spinbutton_defocus(GTK_OBJECT(tbl));
2250 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2251                                       gchar const *old_value, gchar const *new_value,
2252                                       bool is_interactive, gpointer data)
2254     GtkWidget *tbl = GTK_WIDGET(data);
2256     // quit if run by the _changed callbacks
2257     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2258         return;
2259     }
2261     // in turn, prevent callbacks from responding
2262     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2264     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2265     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2267     GtkAdjustment *adj1,*adj2;
2268     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2269     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2270     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2271     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2273     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2275     char const *openstr = NULL;
2276     openstr = repr->attribute("sodipodi:open");
2277     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2279     if (openstr) {
2280         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2281     } else {
2282         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2283     }
2285     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2288 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2289     NULL, /* child_added */
2290     NULL, /* child_removed */
2291     arc_tb_event_attr_changed,
2292     NULL, /* content_changed */
2293     NULL  /* order_changed */
2294 };
2297 static void
2298 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2300     int n_selected = 0;
2301     Inkscape::XML::Node *repr = NULL;
2302     Inkscape::XML::Node *oldrepr = NULL;
2304     for (GSList const *items = selection->itemList();
2305          items != NULL;
2306          items = items->next)
2307     {
2308         if (SP_IS_ARC((SPItem *) items->data)) {
2309             n_selected++;
2310             repr = SP_OBJECT_REPR((SPItem *) items->data);
2311         }
2312     }
2314     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2316     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2317     if (n_selected == 0) {
2318         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2319     } else if (n_selected == 1) {
2320         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2321         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2323         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2325         if (oldrepr) { // remove old listener
2326             sp_repr_remove_listener_by_data(oldrepr, tbl);
2327             Inkscape::GC::release(oldrepr);
2328             oldrepr = 0;
2329             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2330         }
2332         if (repr) {
2333             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2334             Inkscape::GC::anchor(repr);
2335             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2336             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2337         }
2338     } else {
2339         // FIXME: implement averaging of all parameters for multiple selected
2340         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2341         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2342         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2343     }
2347 static GtkWidget *
2348 sp_arc_toolbox_new(SPDesktop *desktop)
2350     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2352     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2353     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2355     GtkTooltips *tt = gtk_tooltips_new();
2357     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2359     /* Start */
2360     {
2361         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2362                                          "tools.shapes.arc", "start", 0.0,
2363                                          NULL, tbl, TRUE, "altx-arc",
2364                                          -360.0, 360.0, 1.0, 10.0,
2365                                          sp_arctb_start_value_changed);
2366         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2367     }
2369     /* End */
2370     {
2371         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2372                                          "tools.shapes.arc", "end", 0.0,
2373                                          NULL, tbl, FALSE, NULL,
2374                                          -360.0, 360.0, 1.0, 10.0,
2375                                          sp_arctb_end_value_changed);
2376         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2377     }
2379     /* Segments / Pie checkbox */
2380     {
2381         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2382         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2383         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2385         gchar const *openstr = NULL;
2386         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2387         if (!openstr || (openstr && !strcmp(openstr, "false")))
2388             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2389         else
2390             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2392         gtk_widget_show(fscb);
2393         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2394         gtk_container_add(GTK_CONTAINER(hb), fscb);
2395         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2396         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2397     }
2399     /* Make Whole */
2400     {
2401         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2402         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2403         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2404         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2405         gtk_widget_show(b);
2406         gtk_container_add(GTK_CONTAINER(hb), b);
2407         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2408         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2409     }
2411     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2412     // sensitivize make whole and open checkbox
2413     {
2414         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2415         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2416         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2417     }
2419     sigc::connection *connection = new sigc::connection(
2420         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2421         );
2422     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2424     gtk_widget_show_all(tbl);
2425     sp_set_font_size_smaller (tbl);
2427     return tbl;
2433 // toggle button callbacks and updaters
2435 //########################
2436 //##      Dropper       ##
2437 //########################
2439 static void toggle_dropper_color_pick (GtkWidget *button, gpointer data) {
2440     prefs_set_int_attribute ("tools.dropper", "pick", 
2441         // 0 and 1 are backwards here because of pref
2442         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 0 : 1);
2446 /**
2447  * Copy the current saved desktop color to the clipboard as full hex + alpha
2448  * color representation. This is useful for passing values between various 
2449  * input boxes, or directly to xml.
2450  */
2451 /* static void
2452 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2454     GtkWidget *tbl = GTK_WIDGET(obj);
2455     
2456     SPDesktop *desktop = 
2457         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2459    
2460     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2461 }*/
2464 /**
2465  * Copies currently saved desktop color to the clipboard as a hex value. This 
2466  * is useful for editing webpages and needing a value quickly for web
2467  * colors.
2468  * 
2469  * TODO: When the toggle of the dropper is set to not mix color against 
2470  *       page background, this still just gets the color of the page and 
2471  *       doesn't get the actual mixed against background which is needed 
2472  *       for the hex value ppl. want for web pages, etc.
2473  */
2475 /* static void
2476 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2478     GtkWidget *tbl = GTK_WIDGET(obj);
2479     
2480     SPDesktop *desktop = 
2481         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2482     
2483     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2484 }*/
2487 /**
2488  * Sets the input boxes with the changed color and opacity. This is used as a 
2489  * callback for style changing.
2490  */
2491 /* static bool
2492 sp_style_changed (const SPCSSAttr *css, gpointer data)
2494     // GrDrag *drag = (GrDrag *) data;
2495     
2496     // set fill of text entry box
2497     if (css->attribute("fill"))
2498         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2499             css->attribute("fill")); 
2501     // set opacity of text entry box
2502     if (css->attribute("fill-opacity"))
2503         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2504             css->attribute("fill-opacity")); 
2505     
2506     // set fill of text entry box
2507     if (css->attribute("stroke"))
2508         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry, 
2509             css->attribute("stroke")); 
2511     // set opacity of text entry box
2512     if (css->attribute("stroke-opacity"))
2513         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry, 
2514             css->attribute("stroke-opacity"));
2515     return false;
2518 */
2521 /**
2522  * Dropper auxiliary toolbar construction and setup.
2523  *
2524  * TODO: Would like to add swatch of current color.
2525  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2526  *       can drag and drop places. Will provide a nice mixing palette.
2527  */
2528 static GtkWidget *
2529 sp_dropper_toolbox_new(SPDesktop *desktop)
2531     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2533     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2534     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2536     GtkTooltips *tt = gtk_tooltips_new();
2538     
2539     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE, 
2540                        AUX_BETWEEN_BUTTON_GROUPS);
2541     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2544     
2545     /* RGB Input Field */
2546  /*   {
2547         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2548         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2549         gtk_widget_show (dropper_rgba_label);
2550         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
2551         
2552         dropper_rgb_entry = gtk_entry_new ();
2553         sp_dialog_defocus_on_enter (dropper_rgb_entry);
2554         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
2555         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
2556         gtk_tooltips_set_tip(tt, dropper_rgb_entry, 
2557                          _("Hexidecimal representation of last selected "
2558                            "color"), 
2559                          NULL);
2560         gtk_widget_show (dropper_rgb_entry);
2561         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
2562         
2563         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2564                            AUX_BETWEEN_BUTTON_GROUPS);
2565     } */
2566     
2567     /* Opacity Input Field */
2568 /*    {
2569         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2570         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
2571         gtk_widget_show (dropper_opacity_label);
2572         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
2573         
2574         dropper_opacity_entry = gtk_entry_new ();
2575         sp_dialog_defocus_on_enter (dropper_opacity_entry);
2576         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
2577         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
2578         gtk_tooltips_set_tip(tt, dropper_opacity_entry, 
2579                          _("Opacity of last selected color"), 
2580                          NULL);
2581         gtk_widget_show (dropper_opacity_entry);
2582         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
2583         
2584         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2585                            AUX_BETWEEN_BUTTON_GROUPS);
2586     } */
2587     
2588     
2589     /* Copy to Clipboard */
2590 /*    {
2591         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2592         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
2593         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
2594                                       "RGB + Alpha (RGBA) to "
2595                                       "clipboard"), 
2596                              NULL);
2597         gtk_widget_show(b);
2598         gtk_container_add(GTK_CONTAINER(hb), b);
2599         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2600             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
2601         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2602                            AUX_BETWEEN_BUTTON_GROUPS);
2603     } */
2606     /* Copy to Clipboard as HEX */
2607 /*    {
2608         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2609         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
2610         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
2611                                       "hexidecimal RGB without alpha " 
2612                                       "to clipboard"), NULL);
2613         gtk_widget_show(b);
2614         gtk_container_add(GTK_CONTAINER(hb), b);
2615         gtk_signal_connect(GTK_OBJECT(b), "clicked", 
2616             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
2617         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2618                            AUX_BETWEEN_BUTTON_GROUPS);
2619     } */
2620     
2621     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2622     
2623     {
2624         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2625         
2626         GtkWidget *button = 
2627             sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
2628                                      SP_BUTTON_TYPE_TOGGLE,
2629                                      NULL,
2630                                      "pick_color",
2631                                      _("When pressed, picks visible color "
2632                                        "without alpha and when not pressed, "
2633                                        "picks color including its "
2634                                        "alpha"),
2635                                      tt);
2637         gtk_widget_show(button);
2638         gtk_container_add (GTK_CONTAINER (hb), button);
2640         g_signal_connect_after (G_OBJECT (button), "clicked", 
2641                                 G_CALLBACK (toggle_dropper_color_pick), NULL);
2642         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), 
2643                                       !prefs_get_int_attribute ("tools.dropper", 
2644                                                                "pick", 0));
2645         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 
2646                    AUX_BETWEEN_BUTTON_GROUPS);
2647     }
2648    
2649     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2650     
2652     // where new gtkmm stuff should go
2653     
2654     gtk_widget_show_all(tbl);
2655     sp_set_font_size_smaller (tbl);
2657     /*
2658     sigc::connection *connection = new sigc::connection(
2659         desktop->connectSetStyle(
2660             sigc::bind(sigc::ptr_fun(sp_style_changed), 
2661                        desktop)) ); 
2662     
2663     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), 
2664                      connection); */
2665     
2666     return tbl;
2670 //########################
2671 //##    Text Toolbox    ##
2672 //########################
2673 /*
2674 static void
2675 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2677     //Call back for letter sizing spinbutton
2680 static void
2681 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2683     //Call back for line height spinbutton
2686 static void
2687 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2689     //Call back for horizontal kerning spinbutton
2692 static void
2693 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2695     //Call back for vertical kerning spinbutton
2698 static void
2699 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
2701     //Call back for letter rotation spinbutton
2702 }*/
2703 static GtkWidget *
2704 sp_text_toolbox_new(SPDesktop *desktop)
2706     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2707 /*    GtkWidget *us = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(tbl), "units");
2708     GtkTooltips *tt = gtk_tooltips_new();
2709     GtkWidget *group;
2711         //Font Family
2712         {
2713         GtkWidget *c = gtk_combo_new ();
2714         gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2715         gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2716         gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2717         gtk_widget_set_size_request (c, 144, -1);
2718         aux_toolbox_space(tbl, 1);
2719         gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2720         }
2722         //Font Style
2723         {
2724         GtkWidget *c = gtk_combo_new ();
2725         gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2726         gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2727         gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2728         gtk_widget_set_size_request (c, 88, -1);
2729         aux_toolbox_space(tbl, 1);
2730         gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2731         }
2733         //Font Size
2734         {
2735         GtkWidget *c = gtk_combo_new ();
2736         gtk_combo_set_value_in_list ((GtkCombo *) c, FALSE, FALSE);
2737         gtk_combo_set_use_arrows ((GtkCombo *) c, TRUE);
2738         gtk_combo_set_use_arrows_always ((GtkCombo *) c, TRUE);
2739         gtk_widget_set_size_request (c, 64, -1);
2740         aux_toolbox_space(tbl, 1);
2741         gtk_box_pack_start (GTK_BOX (tbl), c, FALSE, FALSE, 0);
2742         }
2744         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2745         //Bold
2746         {
2747         GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_BOLD, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2748         GtkWidget *button = gtk_toggle_button_new ();
2749         gtk_container_add (GTK_CONTAINER (button), px);
2750         gtk_widget_show(button);
2751         gtk_tooltips_set_tip (tt, button, _("Bold"), NULL);
2752         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2753         gtk_widget_set_sensitive(button, TRUE);
2754         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2755         }
2758         //Italic
2759         {
2760         GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_ITALIC, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2761         GtkWidget *button = gtk_toggle_button_new ();
2762         gtk_container_add (GTK_CONTAINER (button), px);
2763         gtk_widget_show(button);
2764         gtk_tooltips_set_tip (tt, button, _("Italics"), NULL);
2765         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2766         gtk_widget_set_sensitive(button, TRUE);
2767         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2768         }
2770         //Underline
2771         {
2772         GtkWidget *px = gtk_image_new_from_stock(GTK_STOCK_UNDERLINE, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2773         GtkWidget *button = gtk_toggle_button_new ();
2774         gtk_container_add (GTK_CONTAINER (button), px);
2775         gtk_widget_show(button);
2776         gtk_tooltips_set_tip (tt, button, _("Underline"), NULL);
2777         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2778         gtk_widget_set_sensitive(button, FALSE);
2779         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
2780         }
2782         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2783         // align left
2784         {
2785         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2786         GtkWidget *b = group = gtk_radio_button_new (NULL);
2787                 gtk_container_add (GTK_CONTAINER (b), px);
2788         gtk_tooltips_set_tip (tt, b, _("Align lines left"), NULL);
2789         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2790         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2791         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2792         }
2794         // align center
2795         {
2796         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2797         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2798                 gtk_container_add (GTK_CONTAINER (b), px);
2799         // TRANSLATORS: `Center' here is a verb.
2800         gtk_tooltips_set_tip (tt, b, _("Center lines"), NULL);
2801                 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2802         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2803         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2804         }
2806         // align right
2807         {
2808         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2809         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2810                 gtk_container_add (GTK_CONTAINER (b), px);
2811         gtk_tooltips_set_tip (tt, b, _("Align lines right"), NULL);
2812         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2813         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2814         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2815         }
2817         // full justification
2818         {
2819         GtkWidget *px = gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, Inkscape::ICON_SIZE_SMALL_TOOLBAR);
2820         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2821                 gtk_container_add (GTK_CONTAINER (b), px);
2822         gtk_tooltips_set_tip (tt, b, _("Full justification"), NULL);
2823         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2824         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2825         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2826         }
2827         
2828                 
2829         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2830                 
2831         // horizontal
2832         {
2833         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
2834         GtkWidget *b = group = gtk_radio_button_new (NULL);
2835                 gtk_container_add (GTK_CONTAINER (b), px);
2836         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
2837         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2838         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2839         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2840         }
2842         // vertical
2843         {
2844         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
2845         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
2846                 gtk_container_add (GTK_CONTAINER (b), px);
2847         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
2848         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
2849         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
2850         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
2851         }
2853         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2855         // letter spacing
2856     {
2857         {
2858         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
2859         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2860         gtk_container_add (GTK_CONTAINER (hb), image);
2861         gtk_widget_show(image);
2862         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2863         }
2864     
2865         {
2866             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
2867                                              "tools.text", "letter_spacing", 0.0,
2868                                              us, tbl, FALSE, NULL,
2869                                              -1000.0, 1000.0, 0.1, 0.1,
2870                                              sp_text_letter_changed, 0.1, 1);
2871             gtk_widget_set_size_request (hb, 45, 6);
2872             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
2873         }
2874     }
2876         // line spacing
2877     {
2878         {
2879         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
2880         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2881         gtk_container_add (GTK_CONTAINER (hb), image);
2882         gtk_widget_show(image);
2883         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2884         }
2885     
2886         {
2887             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
2888                                              "tools.text", "line_spacing", 0,
2889                                              us, tbl, FALSE, NULL,
2890                                              -1000.0, 1000.0, 0.1, 0.1,
2891                                              sp_text_line_changed, 0.1, 1);
2892             gtk_widget_set_size_request (hb, 45, 0);
2893             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
2894         }
2895     }
2898     // horizontal kerning/vertical kerning units menu: create
2899     GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
2900     sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
2901     sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
2903     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2905     // horizontal kerning
2906     {
2907         {
2908         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
2909         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2910         gtk_container_add (GTK_CONTAINER (hb), image);
2911         gtk_widget_show(image);
2912         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2913         }
2915         {
2916             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
2917                                              "tools.text", "horizontal_kerning", 0,
2918                                              us, tbl, FALSE, NULL,
2919                                              -100.00, 100.00, 0.01, 0.1,
2920                                              sp_text_horiz_kern_changed);
2921             gtk_widget_set_size_request (hb, 45, 0);
2922             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
2923         }
2924     }
2926     // vertical kerning
2927     {
2928         {
2929         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
2930         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2931         gtk_container_add (GTK_CONTAINER (hb), image);
2932         gtk_widget_show(image);
2933         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2934         }
2935     
2936         {
2937             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
2938                                              "tools.text", "vertical_kerning", 0,
2939                                              us, tbl, FALSE, NULL,
2940                                              -100.00, 100.00, 0.01, 0.1,
2941                                              sp_text_vert_kern_changed);
2942             gtk_widget_set_size_request (hb, 45, 0);
2943             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
2944         }
2945     }
2947     // add the units menu
2948     gtk_widget_show(us);
2949     gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
2950     gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
2951     }
2953         // letter rotation
2954     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
2955     {
2956         {
2957         GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
2958         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2959         gtk_container_add (GTK_CONTAINER (hb), image);
2960         gtk_widget_show(image);
2961         gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
2962         }
2963         {
2964             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
2965                                              "tools.text", "letter_rotation", 0,
2966                                              us, tbl, FALSE, NULL,
2967                                              -180.0, 180.0, 0.1, 0.1,
2968                                              sp_text_letter_rotation_changed, 0.1, 1);
2969             gtk_widget_set_size_request (hb, 45, 0);
2970             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
2971         }
2972         // rotation degree label
2973         {
2974         GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
2975         gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
2976         }
2977     }
2978         
2979         // Remove Manual Kerns
2980         {
2981         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
2982         GtkWidget *button = gtk_button_new ();
2983         gtk_container_add (GTK_CONTAINER (button), px);
2984         gtk_widget_show(button);
2985         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
2986         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2987         gtk_widget_set_sensitive(button, TRUE);
2988         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2989         }
2991     gtk_widget_show_all(tbl);
2992     sp_set_font_size_smaller (tbl);
2994 */    return tbl;
2996 } // end of sp_text_toolbox_new()
2999 //#########################
3000 //##  Connector Toolbox  ##
3001 //#########################
3003 static void sp_connector_path_set_avoid(void)
3005     cc_selection_set_avoid(true);
3009 static void sp_connector_path_set_ignore(void)
3011     cc_selection_set_avoid(false);
3015 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
3017     // quit if run by the _changed callbacks
3018     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3019         return;
3020     }
3021         
3022     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
3023             "desktop");
3024     SPDocument *doc = sp_desktop_document(desktop);
3026     if (!sp_document_get_undo_sensitive(doc))
3027     {
3028         return;
3029     }
3031     // in turn, prevent callbacks from responding
3032     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3033     
3034     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3035     
3036     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
3037     SP_OBJECT(desktop->namedview)->updateRepr();
3038     
3039     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
3040     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
3041         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
3042         NR::Matrix m = NR::identity();
3043         avoid_item_move(&m, item);
3044     }
3046     if (items) {
3047         g_slist_free(items);
3048     }
3049     
3050     sp_document_done(doc);
3052     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3053     
3054     spinbutton_defocus(GTK_OBJECT(tbl));
3058 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
3059         gchar const *name, gchar const *old_value, gchar const *new_value,
3060         bool is_interactive, gpointer data)
3062     GtkWidget *tbl = GTK_WIDGET(data);
3064     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3065         return;
3066     }
3067     if (strcmp(name, "inkscape:connector-spacing") != 0) {
3068         return;
3069     }
3071     GtkAdjustment *adj = (GtkAdjustment*)
3072             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
3073     gdouble spacing = defaultConnSpacing;
3074     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
3075     
3076     gtk_adjustment_set_value(adj, spacing);
3080 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
3081     NULL, /* child_added */
3082     NULL, /* child_removed */
3083     connector_tb_event_attr_changed,
3084     NULL, /* content_changed */
3085     NULL  /* order_changed */
3086 };
3089 static GtkWidget *
3090 sp_connector_toolbox_new(SPDesktop *desktop)
3092     GtkTooltips *tt = gtk_tooltips_new();
3093     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3094     
3095     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3096     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3098     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3099             AUX_BETWEEN_BUTTON_GROUPS);
3101     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_DECORATION,
3102             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
3103             tt, _("Make connectors avoid selected objects"));
3105     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_DECORATION,
3106             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
3107             tt, _("Make connectors ignore selected objects"));
3109     //  interval
3110     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3111             AUX_BETWEEN_BUTTON_GROUPS);
3113     // Spacing spinbox
3114     {
3115         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
3116                 _("The amount of space left around objects by auto-routing connectors"),
3117                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
3118                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
3119                 connector_spacing_changed, 1, 0);
3121         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
3122                 AUX_SPACING);
3123     }
3125     gtk_widget_show_all(tbl);
3126     sp_set_font_size_smaller (tbl);
3127     
3128     // Code to watch for changes to the connector-spacing attribute in
3129     // the XML.
3130     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
3131     g_assert(repr != NULL);
3132         
3133     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
3134             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
3135     
3136     if (oldrepr) { // remove old listener
3137         sp_repr_remove_listener_by_data(oldrepr, tbl);
3138         Inkscape::GC::release(oldrepr);
3139         oldrepr = NULL;
3140         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
3141     }
3143     if (repr) {
3144         g_object_set_data(G_OBJECT(tbl), "repr", repr);
3145         Inkscape::GC::anchor(repr);
3146         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
3147         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
3148     }
3149     
3150     return tbl;
3152 } // end of sp_connector_toolbox_new()
3155 /*
3156   Local Variables:
3157   mode:c++
3158   c-file-style:"stroustrup"
3159   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
3160   indent-tabs-mode:nil
3161   fill-column:99
3162   End:
3163 */
3164 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :