Code

Switched zoom toobar to stock GTK+ toolbars
[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 *   Jon A. Cruz <jon@joncruz.org>
19 *
20 * Copyright (C) 2004 David Turner
21 * Copyright (C) 2003 MenTaLguY
22 * Copyright (C) 1999-2006 authors
23 * Copyright (C) 2001-2002 Ximian, Inc.
24 *
25 * Released under GNU GPL, read the file 'COPYING' for more information
26 */
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <gtkmm.h>
33 #include <gtk/gtk.h>
34 #include <iostream>
35 #include <sstream>
37 #include "widgets/button.h"
38 #include "widgets/widget-sizes.h"
39 #include "widgets/spw-utilities.h"
40 #include "widgets/spinbutton-events.h"
41 #include "dialogs/text-edit.h"
43 #include "ui/widget/style-swatch.h"
45 #include "prefs-utils.h"
46 #include "verbs.h"
47 #include "sp-namedview.h"
48 #include "desktop.h"
49 #include "desktop-handles.h"
50 #include "nodepath.h"
51 #include "xml/repr.h"
52 #include "xml/node-event-vector.h"
53 #include <glibmm/i18n.h>
54 #include "helper/unit-menu.h"
55 #include "helper/units.h"
57 #include "inkscape.h"
58 #include "conn-avoid-ref.h"
61 #include "select-toolbar.h"
62 #include "gradient-toolbar.h"
64 #include "connector-context.h"
65 #include "sp-rect.h"
66 #include "sp-star.h"
67 #include "sp-spiral.h"
68 #include "sp-ellipse.h"
69 #include "sp-text.h"
70 #include "sp-flowtext.h"
71 #include "style.h"
72 #include "selection.h"
73 #include "document-private.h"
74 #include "desktop-style.h"
75 #include "../libnrtype/font-lister.h"
76 #include "../connection-pool.h"
77 #include "../prefs-utils.h"
78 #include "../inkscape-stock.h"
79 #include "icon.h"
80 #include "graphlayout/graphlayout.h"
82 #include "mod360.h"
84 #include "toolbox.h"
86 #include "flood-context.h"
88 #include "ink-action.h"
89 #include "ege-adjustment-action.h"
90 #include "ege-output-action.h"
91 #include "ege-select-one-action.h"
92 #include "helper/unit-tracker.h"
94 using Inkscape::UnitTracker;
96 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
97 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
99 static GtkWidget *sp_node_toolbox_new(SPDesktop *desktop);
100 static GtkWidget *sp_zoom_toolbox_new(SPDesktop *desktop);
101 static GtkWidget *sp_star_toolbox_new(SPDesktop *desktop);
102 static GtkWidget *sp_arc_toolbox_new(SPDesktop *desktop);
103 static GtkWidget *sp_rect_toolbox_new(SPDesktop *desktop);
104 static GtkWidget *sp_spiral_toolbox_new(SPDesktop *desktop);
105 static GtkWidget *sp_pencil_toolbox_new(SPDesktop *desktop);
106 static GtkWidget *sp_pen_toolbox_new(SPDesktop *desktop);
107 static GtkWidget *sp_calligraphy_toolbox_new(SPDesktop *desktop);
108 static GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
109 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
110 static GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
111 static GtkWidget *sp_paintbucket_toolbox_new(SPDesktop *desktop);
113 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
116 static struct {
117     gchar const *type_name;
118     gchar const *data_name;
119     sp_verb_t verb;
120     sp_verb_t doubleclick_verb;
121 } const tools[] = {
122     { "SPSelectContext",   "select_tool",    SP_VERB_CONTEXT_SELECT,  SP_VERB_CONTEXT_SELECT_PREFS},
123     { "SPNodeContext",     "node_tool",      SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
124     { "SPZoomContext",     "zoom_tool",      SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
125     { "SPRectContext",     "rect_tool",      SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
126     { "SPArcContext",      "arc_tool",       SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
127     { "SPStarContext",     "star_tool",      SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
128     { "SPSpiralContext",   "spiral_tool",    SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
129     { "SPPencilContext",   "pencil_tool",    SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
130     { "SPPenContext",      "pen_tool",       SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
131     { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
132     { "SPFloodContext",    "paintbucket_tool",     SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
133     { "SPTextContext",     "text_tool",      SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
134     { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
135     { "SPGradientContext", "gradient_tool",  SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
136     { "SPDropperContext",  "dropper_tool",   SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
137     { NULL, NULL, 0, 0 }
138 };
140 static struct {
141     gchar const *type_name;
142     gchar const *data_name;
143     GtkWidget *(*create_func)(SPDesktop *desktop);
144 } const aux_toolboxes[] = {
145     { "SPSelectContext", "select_toolbox", sp_select_toolbox_new },
146     { "SPNodeContext",   "node_toolbox",   sp_node_toolbox_new },
147     { "SPZoomContext",   "zoom_toolbox",   sp_zoom_toolbox_new },
148     { "SPStarContext",   "star_toolbox",   sp_star_toolbox_new },
149     { "SPRectContext",   "rect_toolbox",   sp_rect_toolbox_new },
150     { "SPArcContext",    "arc_toolbox",    sp_arc_toolbox_new },
151     { "SPSpiralContext", "spiral_toolbox", sp_spiral_toolbox_new },
152     { "SPPencilContext", "pencil_toolbox", sp_pencil_toolbox_new },
153     { "SPPenContext", "pen_toolbox", sp_pen_toolbox_new },
154     { "SPDynaDrawContext", "calligraphy_toolbox", sp_calligraphy_toolbox_new },
155     { "SPTextContext",   "text_toolbox",   sp_text_toolbox_new },
156     { "SPDropperContext", "dropper_toolbox", sp_dropper_toolbox_new },
157     { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new },
158     { "SPConnectorContext", "connector_toolbox", sp_connector_toolbox_new },
159     { "SPFloodContext",  "paintbucket_toolbox",  sp_paintbucket_toolbox_new },
160     { NULL, NULL, NULL }
161 };
163 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
165 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
167 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
168 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
170 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
171 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
173 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
174 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
176 /* Global text entry widgets necessary for update */
177 /* GtkWidget *dropper_rgb_entry,
178           *dropper_opacity_entry ; */
179 // should be made a private member once this is converted to class
181 static void delete_connection(GObject *obj, sigc::connection *connection) {
182     connection->disconnect();
183     delete connection;
186 static GtkWidget *
187 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
188                       GtkTooltips *tt, gchar const *tip)
190     GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
191     gtk_widget_show(b);
192     if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
193     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
195     return b;
198 GtkWidget *
199 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
200                                                  Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
201                                                  Inkscape::UI::View::View *view, GtkTooltips *tt)
203     SPAction *action = verb->get_action(view);
204     if (!action) return NULL;
206     SPAction *doubleclick_action;
207     if (doubleclick_verb)
208         doubleclick_action = doubleclick_verb->get_action(view);
209     else
210         doubleclick_action = NULL;
212     /* fixme: Handle sensitive/unsensitive */
213     /* fixme: Implement sp_button_new_from_action */
214     GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
215     gtk_widget_show(b);
216     gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
218     return b;
221 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
222                                            Inkscape::UI::View::View *view, GtkTooltips *tt)
224     return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
227 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
228                                                    Inkscape::UI::View::View *view, GtkTooltips *tt)
230     return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
234 static void trigger_sp_action( GtkAction* act, gpointer user_data )
236     SPAction* targetAction = SP_ACTION(user_data);
237     if ( targetAction ) {
238         sp_action_perform( targetAction, NULL );
239     }
242 static void sp_action_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data)
244     if ( data ) {
245         GtkAction* act = GTK_ACTION(data);
246         gtk_action_set_sensitive( act, sensitive );
247     }
250 static SPActionEventVector action_event_vector = {
251     {NULL},
252     NULL,
253     NULL,
254     sp_action_action_set_sensitive,
255     NULL,
256     NULL
257 };
259 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
261     GtkAction* act = 0;
263     SPAction* targetAction = verb->get_action(view);
264     InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size  );
265     act = GTK_ACTION(inky);
266     gtk_action_set_sensitive( act, targetAction->sensitive );
268     g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
270     SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
271     nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
273     return act;
276 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
278     Inkscape::UI::View::View *view = desktop;
279     gint verbsToUse[] = {
280         // disabled until we have icons for them:
281         //find
282         //SP_VERB_EDIT_TILE,
283         //SP_VERB_EDIT_UNTILE,
284         SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
285         SP_VERB_DIALOG_DISPLAY,
286         SP_VERB_DIALOG_FILL_STROKE,
287         SP_VERB_DIALOG_NAMEDVIEW,
288         SP_VERB_DIALOG_TEXT,
289         SP_VERB_DIALOG_XML_EDITOR,
290         SP_VERB_EDIT_CLONE,
291         SP_VERB_EDIT_COPY,
292         SP_VERB_EDIT_CUT,
293         SP_VERB_EDIT_DUPLICATE,
294         SP_VERB_EDIT_PASTE,
295         SP_VERB_EDIT_REDO,
296         SP_VERB_EDIT_UNDO,
297         SP_VERB_EDIT_UNLINK_CLONE,
298         SP_VERB_FILE_EXPORT,
299         SP_VERB_FILE_IMPORT,
300         SP_VERB_FILE_NEW,
301         SP_VERB_FILE_OPEN,
302         SP_VERB_FILE_PRINT,
303         SP_VERB_FILE_SAVE,
304         SP_VERB_SELECTION_GROUP,
305         SP_VERB_SELECTION_UNGROUP,
306         SP_VERB_ZOOM_1_1,
307         SP_VERB_ZOOM_1_2,
308         SP_VERB_ZOOM_2_1,
309         SP_VERB_ZOOM_DRAWING,
310         SP_VERB_ZOOM_IN,
311         SP_VERB_ZOOM_NEXT,
312         SP_VERB_ZOOM_OUT,
313         SP_VERB_ZOOM_PAGE,
314         SP_VERB_ZOOM_PAGE_WIDTH,
315         SP_VERB_ZOOM_PREV,
316         SP_VERB_ZOOM_SELECTION,
317     };
319     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
320     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
322     static std::map<SPDesktop*, GtkActionGroup*> groups;
323     GtkActionGroup* mainActions = 0;
324     if ( groups.find(desktop) != groups.end() ) {
325         mainActions = groups[desktop];
326     }
328     if ( !mainActions ) {
329         mainActions = gtk_action_group_new("main");
330         groups[desktop] = mainActions;
331     }
333     for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
334         Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
335         if ( verb ) {
336             if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
337                 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
338                 gtk_action_group_add_action( mainActions, act );
339             }
340         }
341     }
343     return mainActions;
347 GtkWidget *
348 sp_tool_toolbox_new()
350     GtkTooltips *tt = gtk_tooltips_new();
351     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
353     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
354     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
356     gtk_widget_set_sensitive(tb, FALSE);
358     GtkWidget *hb = gtk_handle_box_new();
359     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
360     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
361     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
363     gtk_container_add(GTK_CONTAINER(hb), tb);
364     gtk_widget_show(GTK_WIDGET(tb));
366     sigc::connection* conn = new sigc::connection;
367     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
369     return hb;
372 static void
373 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
375     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
376     gtk_widget_queue_resize(child);
379 static void
380 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
382     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
383     gtk_widget_queue_resize(child);
386 GtkWidget *
387 sp_aux_toolbox_new()
389     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
391     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
392     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
393     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
394     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
395     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
397     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
398     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
400     gtk_widget_set_sensitive(tb, FALSE);
402     GtkWidget *hb = gtk_handle_box_new();
403     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
404     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
405     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
407     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
408     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
410     gtk_container_add(GTK_CONTAINER(hb), tb);
411     gtk_widget_show(GTK_WIDGET(tb));
413     sigc::connection* conn = new sigc::connection;
414     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
416     return hb;
419 //####################################
420 //# Commands Bar
421 //####################################
423 GtkWidget *
424 sp_commands_toolbox_new()
426     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
428     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
429     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
430     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
431     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
432     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
434     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
435     gtk_widget_set_sensitive(tb, FALSE);
437     GtkWidget *hb = gtk_handle_box_new();
438     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
439     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
440     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
442     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
443     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
445     gtk_container_add(GTK_CONTAINER(hb), tb);
446     gtk_widget_show(GTK_WIDGET(tb));
448     sigc::connection* conn = new sigc::connection;
449     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
451     return hb;
455 //####################################
456 //# node editing callbacks
457 //####################################
459 void
460 sp_node_path_edit_add(void)
462     sp_node_selected_add_node();
465 void
466 sp_node_path_edit_delete(void)
468     sp_node_selected_delete();
471 void
472 sp_node_path_edit_delete_segment(void)
474     sp_node_selected_delete_segment();
477 void
478 sp_node_path_edit_break(void)
480     sp_node_selected_break();
483 void
484 sp_node_path_edit_join(void)
486     sp_node_selected_join();
489 void
490 sp_node_path_edit_join_segment(void)
492     sp_node_selected_join_segment();
495 void
496 sp_node_path_edit_toline(void)
498     sp_node_selected_set_line_type(NR_LINETO);
501 void
502 sp_node_path_edit_tocurve(void)
504     sp_node_selected_set_line_type(NR_CURVETO);
507 void
508 sp_node_path_edit_cusp(void)
510     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
513 void
514 sp_node_path_edit_smooth(void)
516     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
519 void
520 sp_node_path_edit_symmetrical(void)
522     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
525 static void toggle_show_handles (GtkWidget *button, gpointer data) {
526     bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
527     prefs_set_int_attribute ("tools.nodes", "show_handles",  show ? 1 : 0);
528     sp_nodepath_show_handles(show);
531 //################################
532 //##    Node Editing Toolbox    ##
533 //################################
535 static GtkWidget *
536 sp_node_toolbox_new(SPDesktop *desktop)
538     Inkscape::UI::View::View *view = desktop;
540     GtkTooltips *tt = gtk_tooltips_new();
541     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
543     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
545     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
546         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
547     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
548         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
550     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
552     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
553         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
554     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
555         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
557     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
558         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
560     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
561         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
563     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
565     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
566         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
568     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
569         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
571     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
572         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
574     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
576     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
577         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
579     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
580         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
582     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
584     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
586     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
588     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
590     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
591     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
593     {
594     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
595                                               SP_BUTTON_TYPE_TOGGLE,
596                                               NULL,
597                                               "nodes_show_handles",
598                                               _("Show the Bezier handles of selected nodes"),
599                                               tt);
600     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
601     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
602     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
603     }
605     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
606     gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
608     gtk_widget_show_all(tb);
610     return tb;
612 } // end of sp_node_toolbox_new()
615 //########################
616 //##    Zoom Toolbox    ##
617 //########################
619 static GtkWidget *
620 sp_zoom_toolbox_new(SPDesktop *desktop)
622     gchar const * descr =
623         "<ui>"
624         "  <toolbar name='ZoomToolbar'>"
625         "    <toolitem action='ZoomIn' />"
626         "    <toolitem action='ZoomOut' />"
627         "    <separator />"
628         "    <toolitem action='ZoomSelection' />"
629         "    <toolitem action='ZoomDrawing' />"
630         "    <toolitem action='ZoomPage' />"
631         "    <toolitem action='ZoomPageWidth' />"
632         "    <separator />"
633         "    <toolitem action='ZoomPrev' />"
634         "    <toolitem action='ZoomNext' />"
635         "    <separator />"
636         "    <toolitem action='Zoom1:0' />"
637         "    <toolitem action='Zoom1:2' />"
638         "    <toolitem action='Zoom2:1' />"
639         "  </toolbar>"
640         "</ui>";
641     GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
644     GtkUIManager* mgr = gtk_ui_manager_new();
645     GError* errVal = 0;
647     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
648     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
650     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/ZoomToolbar" );
651     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
652     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
653     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
654     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
656     return toolBar;
657 } // end of sp_zoom_toolbox_new()
659 void
660 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
662     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")));
666 void
667 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
669     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")));
672 void
673 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
675     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")));
678 static void
679 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
681     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
682     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
684     if (old_desktop) {
685         GList *children, *iter;
687         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
688         for ( iter = children ; iter ; iter = iter->next ) {
689             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
690         }
691         g_list_free(children);
692     }
694     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
696     if (desktop) {
697         gtk_widget_set_sensitive(toolbox, TRUE);
698         setup_func(toolbox, desktop);
699         update_func(desktop, desktop->event_context, toolbox);
700         *conn = desktop->connectEventContextChanged
701             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
702     } else {
703         gtk_widget_set_sensitive(toolbox, FALSE);
704     }
706 } // end of toolbox_set_desktop()
709 static void
710 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
712     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
713     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
714     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
716     for (int i = 0 ; tools[i].type_name ; i++ ) {
717         GtkWidget *button =
718             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
719                                                               SP_BUTTON_TYPE_TOGGLE,
720                                                               Inkscape::Verb::get(tools[i].verb),
721                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
722                                                               desktop,
723                                                               tooltips );
725         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
726                            (gpointer)button );
727     }
731 static void
732 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
734     gchar const *const tname = ( eventcontext
735                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
736                                  : NULL );
737     for (int i = 0 ; tools[i].type_name ; i++ ) {
738         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
739         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
740     }
743 static void
744 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
746     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
748     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
749         GtkWidget *sub_toolbox;
750         if (aux_toolboxes[i].create_func == NULL)
751             sub_toolbox = sp_empty_toolbox_new(desktop);
752         else
753             sub_toolbox = aux_toolboxes[i].create_func(desktop);
755         gtk_size_group_add_widget( grouper, sub_toolbox );
757         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
758         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
759     }
760     g_object_unref( G_OBJECT(grouper) );
763 static void
764 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
766     gchar const *tname = ( eventcontext
767                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
768                            : NULL );
769     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
770         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
771         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
772             gtk_widget_show_all(sub_toolbox);
773             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
774         } else {
775             gtk_widget_hide(sub_toolbox);
776         }
777     }
780 static void
781 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
783     gchar const * descr =
784         "<ui>"
785         "  <toolbar name='CommandsToolbar'>"
786         "    <toolitem action='FileNew' />"
787         "    <toolitem action='FileOpen' />"
788         "    <toolitem action='FileSave' />"
789         "    <toolitem action='FilePrint' />"
790         "    <separator />"
791         "    <toolitem action='FileImport' />"
792         "    <toolitem action='FileExport' />"
793         "    <separator />"
794         "    <toolitem action='EditUndo' />"
795         "    <toolitem action='EditRedo' />"
796         "    <separator />"
797         "    <toolitem action='EditCopy' />"
798         "    <toolitem action='EditCut' />"
799         "    <toolitem action='EditPaste' />"
800         "    <separator />"
801         "    <toolitem action='ZoomSelection' />"
802         "    <toolitem action='ZoomDrawing' />"
803         "    <toolitem action='ZoomPage' />"
804         "    <separator />"
805         "    <toolitem action='EditDuplicate' />"
806         "    <toolitem action='EditClone' />"
807         "    <toolitem action='EditUnlinkClone' />"
808         "    <separator />"
809         "    <toolitem action='SelectionGroup' />"
810         "    <toolitem action='SelectionUnGroup' />"
811         "    <separator />"
812         "    <toolitem action='DialogFillStroke' />"
813         "    <toolitem action='DialogText' />"
814         "    <toolitem action='DialogXMLEditor' />"
815         "    <toolitem action='DialogAlignDistribute' />"
816         "    <separator />"
817         "    <toolitem action='DialogPreferences' />"
818         "    <toolitem action='DialogDocumentProperties' />"
819         "  </toolbar>"
820         "</ui>";
821     GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
824     GtkUIManager* mgr = gtk_ui_manager_new();
825     GError* errVal = 0;
827     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
828     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
830     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
831     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
832     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
833     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
834     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
837     gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
840 static void
841 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
845 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
847     gtk_widget_show(toolbox_toplevel);
848     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
850     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
851     if (!shown_toolbox) {
852         return;
853     }
854     gtk_widget_show(toolbox);
856     // need to show the spacer, or the padding will be off
857     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
858     gtk_widget_show(spacer);
860     gtk_widget_show_all(shown_toolbox);
863 void
864 aux_toolbox_space(GtkWidget *tb, gint space)
866     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
869 static GtkWidget *
870 sp_empty_toolbox_new(SPDesktop *desktop)
872     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
873     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
874     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
876     gtk_widget_show_all(tbl);
877     sp_set_font_size_smaller (tbl);
879     return tbl;
882 // helper UI functions
884 GtkWidget *
885 sp_tb_spinbutton(
886     gchar *label, gchar const *tooltip,
887     gchar const *path, gchar const *data, gdouble def,
888     GtkWidget *us,
889     GtkWidget *tbl,
890     gboolean altx, gchar const *altx_mark,
891     gdouble lower, gdouble upper, gdouble step, gdouble page,
892     void (*callback)(GtkAdjustment *, GtkWidget *),
893     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
895     GtkTooltips *tt = gtk_tooltips_new();
897     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
899     GtkWidget *l = gtk_label_new(label);
900     gtk_widget_show(l);
901     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
902     gtk_container_add(GTK_CONTAINER(hb), l);
904     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
905                                       lower, upper, step, page, page);
906     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
907     if (us)
908         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
910     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
911     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
912     if (altx)
913         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
914     gtk_widget_set_size_request(sb,
915                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
916                                 AUX_SPINBUTTON_HEIGHT);
917     gtk_widget_show(sb);
918     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
919     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
920     gtk_container_add(GTK_CONTAINER(hb), sb);
921     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
923     return hb;
926 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
927                                                        gchar const *label, gchar const *tooltip,
928                                                        gchar const *path, gchar const *data, gdouble def,
929                                                        GtkWidget *focusTarget,
930                                                        GtkWidget *us,
931                                                        GtkWidget *dataKludge,
932                                                        gboolean altx, gchar const *altx_mark,
933                                                        gdouble lower, gdouble upper, gdouble step, gdouble page,
934                                                        gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
935                                                        void (*callback)(GtkAdjustment *, GtkWidget *),
936                                                        gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
938     GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
939                                                              lower, upper, step, page, page ) );
940     if (us) {
941         sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
942     }
944     gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
946     EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
948     if ( (descrCount > 0) && descrLabels && descrValues ) {
949         ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
950     }
952     if ( focusTarget ) {
953         ege_adjustment_action_set_focuswidget( act, focusTarget );
954     }
956     if ( altx && altx_mark ) {
957         g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
958     }
960     if ( dataKludge ) {
961         gtk_object_set_data( GTK_OBJECT(dataKludge), data, adj );
962     }
964     // Using a cast just to make sure we pass in the right kind of function pointer
965     g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
967     return act;
971 #define MODE_LABEL_WIDTH 70
973 //########################
974 //##       Star         ##
975 //########################
977 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
979     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
981     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
982         // do not remember prefs if this call is initiated by an undo change, because undoing object
983         // creation sets bogus values to its attributes before it is deleted
984         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
985     }
987     // quit if run by the attr_changed listener
988     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
989         return;
990     }
992     // in turn, prevent listener from responding
993     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
995     bool modmade = false;
997     Inkscape::Selection *selection = sp_desktop_selection(desktop);
998     GSList const *items = selection->itemList();
999     for (; items != NULL; items = items->next) {
1000         if (SP_IS_STAR((SPItem *) items->data)) {
1001             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1002             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1003             sp_repr_set_svg_double(repr, "sodipodi:arg2",
1004                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1005                                     + M_PI / (gint)adj->value));
1006             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1007             modmade = true;
1008         }
1009     }
1010     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1011                                    _("Star: Change number of corners"));
1013     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1016 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
1018     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1020     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1021         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1022     }
1024     // quit if run by the attr_changed listener
1025     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1026         return;
1027     }
1029     // in turn, prevent listener from responding
1030     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1032     bool modmade = false;
1033     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1034     GSList const *items = selection->itemList();
1035     for (; items != NULL; items = items->next) {
1036         if (SP_IS_STAR((SPItem *) items->data)) {
1037             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1039             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1040             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1041             if (r2 < r1) {
1042                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1043             } else {
1044                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1045             }
1047             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1048             modmade = true;
1049         }
1050     }
1052     if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1053                                    _("Star: Change spoke ratio"));
1055     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1058 static void sp_stb_sides_flat_state_changed( GtkToggleAction *act, GtkObject *dataKludge )
1060     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1061     bool flat = gtk_toggle_action_get_active(act);
1063     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1064         prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1065                                     flat ? "true" : "false" );
1066     }
1068     // quit if run by the attr_changed listener
1069     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1070         return;
1071     }
1073     // in turn, prevent listener from responding
1074     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1076     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1077     GSList const *items = selection->itemList();
1078     GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(dataKludge), "prop_action") );
1079     bool modmade = false;
1081     if ( prop_action ) {
1082         gtk_action_set_sensitive( prop_action, !flat );
1083     }
1085     for (; items != NULL; items = items->next) {
1086         if (SP_IS_STAR((SPItem *) items->data)) {
1087             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1088             repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1089             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1090             modmade = true;
1091         }
1092     }
1094     if (modmade) {
1095         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1096                          flat ? _("Make polygon") : _("Make star"));
1097     }
1099     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1102 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
1104     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1106     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1107         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1108     }
1110     // quit if run by the attr_changed listener
1111     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1112         return;
1113     }
1115     // in turn, prevent listener from responding
1116     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1118     bool modmade = false;
1120     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1121     GSList const *items = selection->itemList();
1122     for (; items != NULL; items = items->next) {
1123         if (SP_IS_STAR((SPItem *) items->data)) {
1124             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1125             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1126             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1127             modmade = true;
1128         }
1129     }
1130     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1131                                    _("Star: Change rounding"));
1133     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1136 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
1138     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1140     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1141         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1142     }
1144     // quit if run by the attr_changed listener
1145     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1146         return;
1147     }
1149     // in turn, prevent listener from responding
1150     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1152     bool modmade = false;
1154     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1155     GSList const *items = selection->itemList();
1156     for (; items != NULL; items = items->next) {
1157         if (SP_IS_STAR((SPItem *) items->data)) {
1158             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1159             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1160             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1161             modmade = true;
1162         }
1163     }
1164     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1165                                    _("Star: Change randomization"));
1167     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1171 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1172                                        gchar const *old_value, gchar const *new_value,
1173                                        bool is_interactive, gpointer data)
1175     GtkWidget *tbl = GTK_WIDGET(data);
1177     // quit if run by the _changed callbacks
1178     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1179         return;
1180     }
1182     // in turn, prevent callbacks from responding
1183     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1185     GtkAdjustment *adj = 0;
1187     if (!strcmp(name, "inkscape:randomized")) {
1188         adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1189         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1190     } else if (!strcmp(name, "inkscape:rounded")) {
1191         adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1192         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1193     } else if (!strcmp(name, "inkscape:flatsided")) {
1194         GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1195         char const *flatsides = repr->attribute("inkscape:flatsided");
1196         if (flatsides && !strcmp(flatsides,"false" )) {
1197             GtkToggleAction* flat2_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat2_action" ) );
1198             gtk_toggle_action_set_active( flat2_action, TRUE );
1199             gtk_action_set_sensitive( prop_action, TRUE );
1200         } else {
1201             GtkToggleAction* flat_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1202             gtk_toggle_action_set_active( flat_action, TRUE );
1203             gtk_action_set_sensitive( prop_action, FALSE );
1204         }
1205     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1206         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1207         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1208         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1209         if (r2 < r1) {
1210             gtk_adjustment_set_value(adj, r2/r1);
1211         } else {
1212             gtk_adjustment_set_value(adj, r1/r2);
1213         }
1214     } else if (!strcmp(name, "sodipodi:sides")) {
1215         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1216         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1217     }
1219     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1223 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1225     NULL, /* child_added */
1226     NULL, /* child_removed */
1227     star_tb_event_attr_changed,
1228     NULL, /* content_changed */
1229     NULL  /* order_changed */
1230 };
1233 /**
1234  *  \param selection Should not be NULL.
1235  */
1236 static void
1237 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1239     int n_selected = 0;
1240     Inkscape::XML::Node *repr = NULL;
1241     Inkscape::XML::Node *oldrepr = NULL;
1243     for (GSList const *items = selection->itemList();
1244          items != NULL;
1245          items = items->next)
1246     {
1247         if (SP_IS_STAR((SPItem *) items->data)) {
1248             n_selected++;
1249             repr = SP_OBJECT_REPR((SPItem *) items->data);
1250         }
1251     }
1253     EgeOutputAction* act = EGE_OUTPUT_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "mode_action") );
1255     if (n_selected == 0) {
1256         g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1257     } else if (n_selected == 1) {
1258         g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1260         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1261         if (oldrepr) { // remove old listener
1262             sp_repr_remove_listener_by_data(oldrepr, tbl);
1263             Inkscape::GC::release(oldrepr);
1264             oldrepr = 0;
1265             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1266         }
1268         if (repr) {
1269             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1270             Inkscape::GC::anchor(repr);
1271             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1272             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1273         }
1274     } else {
1275         // FIXME: implement averaging of all parameters for multiple selected stars
1276         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1277         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1278     }
1282 static void sp_stb_defaults( GtkWidget *widget, GtkWidget *dataKludge )
1284     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1285     // callbacks to lump all the changes for all selected objects in one undo step
1287     GtkAdjustment *adj = 0;
1289     // fixme: make settable in prefs!
1290     gint mag = 5;
1291     gdouble prop = 0.5;
1292     gboolean flat = FALSE;
1293     gdouble randomized = 0;
1294     gdouble rounded = 0;
1296     GtkToggleAction* flat_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(dataKludge), "flat_action" ) );
1297     GtkToggleAction* flat2_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(dataKludge), "flat2_action" ) );
1298     gtk_toggle_action_set_active( flat ? flat_action : flat2_action, TRUE );
1300     GtkAction* sb2 = GTK_ACTION( g_object_get_data(G_OBJECT(dataKludge), "prop_action") );
1301     gtk_action_set_sensitive( sb2, !flat );
1303     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "magnitude") );
1304     gtk_adjustment_set_value(adj, mag);
1305     gtk_adjustment_value_changed(adj);
1307     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "proportion") );
1308     gtk_adjustment_set_value(adj, prop);
1309     gtk_adjustment_value_changed(adj);
1311     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "rounded") );
1312     gtk_adjustment_set_value(adj, rounded);
1313     gtk_adjustment_value_changed(adj);
1315     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "randomized") );
1316     gtk_adjustment_set_value(adj, randomized);
1317     gtk_adjustment_value_changed(adj);
1321 void
1322 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1324     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1325     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1326     GtkWidget *l = gtk_label_new(NULL);
1327     gtk_label_set_markup(GTK_LABEL(l), title);
1328     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1329     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1330     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1334 static GtkWidget *
1335 sp_star_toolbox_new(SPDesktop *desktop)
1337     GtkWidget* holder = gtk_table_new( 1, 2, FALSE );
1339     gchar const * descr =
1340         "<ui>"
1341         "  <toolbar name='StarToolbar'>"
1342         "    <separator />"
1343         "    <toolitem action='StarStateAction' />"
1344         "    <separator />"
1345         "    <toolitem action='FlatAction' />"
1346         "    <toolitem action='FlatAction2' />"
1347         "    <separator />"
1348         "    <toolitem action='MagnitudeAction' />"
1349         "    <toolitem action='SpokeAction' />"
1350         "    <toolitem action='RoundednessAction' />"
1351         "    <toolitem action='RandomizationAction' />"
1352         "    <separator />"
1353         "    <toolitem action='ResetAction' />"
1354         "  </toolbar>"
1355         "</ui>";
1356     GtkActionGroup* mainActions = gtk_action_group_new("main");
1358     {
1359         EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1360         ege_output_action_set_use_markup( act, TRUE );
1361         gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1362         gtk_object_set_data( GTK_OBJECT(holder), "mode_action", act );
1363     }
1365     {
1366         gtk_object_set_data(GTK_OBJECT(holder), "dtw", desktop->canvas);
1367         gtk_object_set_data(GTK_OBJECT(holder), "desktop", desktop);
1369         //EgeAdjustmentAction* calligraphy_angle = 0;
1370         EgeAdjustmentAction* eact = 0;
1371         gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1372         bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1374         /* Flatsided checkbox */
1375         {
1376             InkRadioAction* act = ink_radio_action_new( "FlatAction",
1377                                                         _("Polygon"),
1378                                                         _("Regular polygon (with one handle) instead of a star"),
1379                                                         "star_flat",
1380                                                         Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1381             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1383             InkRadioAction* act2 = ink_radio_action_new( "FlatAction2",
1384                                                          _("Star"),
1385                                                          _("Star instead of a regular polygon (with one handle)"),
1386                                                          "star_angled",
1387                                                          Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1388             gtk_action_group_add_action( mainActions, GTK_ACTION( act2 ) );
1390             // Connect to be in the same radio button group.
1391             gtk_radio_action_set_group( GTK_RADIO_ACTION(act), 0 );
1392             GSList* radioGroup = gtk_radio_action_get_group( GTK_RADIO_ACTION(act) );
1393             gtk_radio_action_set_group( GTK_RADIO_ACTION(act2), radioGroup );
1395             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), isFlatSided );
1396             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act2), !isFlatSided );
1398             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1399             gtk_object_set_data( GTK_OBJECT(holder), "flat_action", act );
1400             gtk_object_set_data( GTK_OBJECT(holder), "flat2_action", act2 );
1401         }
1403         /* Magnitude */
1404         //gchar const* labels[] = {_("tri (default)"), _("quad"), _("pent")};
1405         //gdouble values[] = {3, 4, 5};
1406         eact = create_adjustment_action( "MagnitudeAction",
1407                                          _("Corners:"), _("Number of corners of a polygon or star"),
1408                                          "tools.shapes.star", "magnitude", 3,
1409                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1410                                          3, 1024, 1, 5,
1411                                          0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
1412                                          sp_stb_magnitude_value_changed,
1413                                          1.0, 0 );
1414         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1415         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1417         /* Spoke ratio */
1418         //gchar const* labels2[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1419         //gdouble values2[] = {-90, 0, 30, 90};
1420         eact = create_adjustment_action( "SpokeAction",
1421                                          _("Spoke ratio:"),
1422                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1423                                          // Base radius is the same for the closest handle.
1424                                          _("Base radius to tip radius ratio"),
1425                                          "tools.shapes.star", "proportion", 0.5,
1426                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1427                                          0.01, 1.0, 0.01, 0.1,
1428                                          0, 0, 0, // labels2, values2, G_N_ELEMENTS(labels2),
1429                                          sp_stb_proportion_value_changed );
1430         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1431         g_object_set_data(G_OBJECT(holder), "prop_action", eact);
1433         if ( !isFlatSided ) {
1434             gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1435         } else {
1436             gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1437         }
1439         /* Roundedness */
1440         //gchar const* labels3[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1441         //gdouble values3[] = {-90, 0, 30, 90};
1442         eact = create_adjustment_action( "RoundednessAction",
1443                                          _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1444                                          "tools.shapes.star", "rounded", 0.0,
1445                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1446                                          -100.0, 100.0, 0.01, 0.1,
1447                                          0, 0, 0, // labels3, values3, G_N_ELEMENTS(labels3),
1448                                          sp_stb_rounded_value_changed );
1449         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1450         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1452         /* Randomization */
1453         //gchar const* labels4[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1454         //gdouble values4[] = {-90, 0, 30, 90};
1455         eact = create_adjustment_action( "RandomizationAction",
1456                                          _("Randomized:"), _("Scatter randomly the corners and angles"),
1457                                          "tools.shapes.star", "randomized", 0.0,
1458                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1459                                          -10.0, 10.0, 0.001, 0.01,
1460                                          0, 0, 0, // labels4, values4, G_N_ELEMENTS(labels4),
1461                                          sp_stb_randomized_value_changed, 0.1, 3 );
1462         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1463         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1464     }
1466     {
1467         /* Reset */
1468         {
1469             GtkAction* act = gtk_action_new( "ResetAction",
1470                                              _("Defaults"),
1471                                              _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1472                                              GTK_STOCK_CLEAR );
1473             g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1474             gtk_action_group_add_action( mainActions, act );
1475             gtk_action_set_sensitive( act, TRUE );
1476         }
1477     }
1480     GtkUIManager* mgr = gtk_ui_manager_new();
1481     GError* errVal = 0;
1483     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1484     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1486     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/StarToolbar" );
1487     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1488     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
1491     gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1493     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new stars"));
1494     swatch->setDesktop( desktop );
1495     swatch->setClickVerb( SP_VERB_CONTEXT_STAR_PREFS );
1496     swatch->setWatchedTool( "tools.shapes.star", true );
1497     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1498     gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, 0 );
1500     gtk_widget_show_all(holder);
1501     //sp_set_font_size_smaller (tbl);
1503     sigc::connection *connection = new sigc::connection(
1504         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)holder))
1505         );
1506     g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(delete_connection), connection);
1508     return holder;
1512 //########################
1513 //##       Rect         ##
1514 //########################
1516 static void
1517 sp_rtb_sensitivize (GtkWidget *tbl)
1519     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1520     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1521     GtkAction* not_rounded = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "not_rounded") );
1523     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1524         gtk_action_set_sensitive( not_rounded, FALSE );
1525     } else {
1526         gtk_action_set_sensitive( not_rounded, TRUE );
1527     }
1531 static void
1532 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1533                           void (*setter)(SPRect *, gdouble))
1535     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1537     UnitTracker* tracker = reinterpret_cast<UnitTracker*>(gtk_object_get_data(GTK_OBJECT(tbl), "tracker"));
1538     SPUnit const *unit = tracker->getActiveUnit();
1540     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1541         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1542     }
1544     // quit if run by the attr_changed listener
1545     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1546         return;
1547     }
1549     // in turn, prevent listener from responding
1550     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1552     bool modmade = false;
1553     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1554     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1555         if (SP_IS_RECT(items->data)) {
1556             if (adj->value != 0) {
1557                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1558             } else {
1559                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1560             }
1561             modmade = true;
1562         }
1563     }
1565     sp_rtb_sensitivize (tbl);
1567     if (modmade) {
1568         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
1569                                    _("Change rectangle"));
1570     }
1572     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1574     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1575     spinbutton_defocus(GTK_OBJECT(tbl));
1578 static void
1579 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1581     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1584 static void
1585 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1587     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1590 static void
1591 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1593     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1596 static void
1597 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1599     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1604 static void
1605 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1607     GtkWidget *tbl = GTK_WIDGET(obj);
1609     GtkAdjustment *adj = 0;
1611     adj = GTK_ADJUSTMENT( gtk_object_get_data(obj, "rx") );
1612     gtk_adjustment_set_value(adj, 0.0);
1613     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1614     gtk_adjustment_value_changed(adj);
1616     adj = GTK_ADJUSTMENT( gtk_object_get_data(obj, "ry") );
1617     gtk_adjustment_set_value(adj, 0.0);
1618     gtk_adjustment_value_changed(adj);
1620     sp_rtb_sensitivize (tbl);
1623 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1624                                        gchar const *old_value, gchar const *new_value,
1625                                        bool is_interactive, gpointer data)
1627     GtkWidget *tbl = GTK_WIDGET(data);
1629     // quit if run by the _changed callbacks
1630     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1631         return;
1632     }
1634     // in turn, prevent callbacks from responding
1635     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1637     UnitTracker* tracker = reinterpret_cast<UnitTracker*>( gtk_object_get_data(GTK_OBJECT(tbl), "tracker") );
1638     SPUnit const *unit = tracker->getActiveUnit();
1640     gpointer item = g_object_get_data(G_OBJECT(tbl), "item");
1641     if (item && SP_IS_RECT(item)) {
1642         {
1643             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1644             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1645             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1646         }
1648         {
1649             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1650             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1651             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1652         }
1654         {
1655             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1656             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1657             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1658         }
1660         {
1661             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1662             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1663             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1664         }
1665     }
1667     sp_rtb_sensitivize (tbl);
1669     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1673 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1674     NULL, /* child_added */
1675     NULL, /* child_removed */
1676     rect_tb_event_attr_changed,
1677     NULL, /* content_changed */
1678     NULL  /* order_changed */
1679 };
1681 /**
1682  *  \param selection should not be NULL.
1683  */
1684 static void
1685 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1687     int n_selected = 0;
1688     Inkscape::XML::Node *repr = NULL;
1689     SPItem *item = NULL;
1690     Inkscape::XML::Node *oldrepr = NULL;
1692     for (GSList const *items = selection->itemList();
1693          items != NULL;
1694          items = items->next) {
1695         if (SP_IS_RECT((SPItem *) items->data)) {
1696             n_selected++;
1697             item = (SPItem *) items->data;
1698             repr = SP_OBJECT_REPR(item);
1699         }
1700     }
1702     EgeOutputAction* act = EGE_OUTPUT_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "mode_action") );
1704     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1706     if (n_selected == 0) {
1707         g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1709         GtkAction* w = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "width_action") );
1710         gtk_action_set_sensitive(w, FALSE);
1711         GtkAction* h = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "height_action") );
1712         gtk_action_set_sensitive(h, FALSE);
1714     } else if (n_selected == 1) {
1715         g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1716         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1718         GtkAction* w = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "width_action") );
1719         gtk_action_set_sensitive(w, TRUE);
1720         GtkAction* h = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "height_action") );
1721         gtk_action_set_sensitive(h, TRUE);
1723         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1724         if (oldrepr) { // remove old listener
1725             sp_repr_remove_listener_by_data(oldrepr, tbl);
1726             Inkscape::GC::release(oldrepr);
1727             oldrepr = 0;
1728             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1729             g_object_set_data(G_OBJECT(tbl), "item", NULL);
1730         }
1731         if (repr) {
1732             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1733             g_object_set_data(G_OBJECT(tbl), "item", item);
1734             Inkscape::GC::anchor(repr);
1735             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1736             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1737         }
1738     } else {
1739         // FIXME: implement averaging of all parameters for multiple selected
1740         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1741         g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1742         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1743     }
1747 static GtkWidget *
1748 sp_rect_toolbox_new(SPDesktop *desktop)
1750     GtkWidget *holder = gtk_hbox_new(FALSE, 0);
1751     gtk_object_set_data(GTK_OBJECT(holder), "dtw", desktop->canvas);
1752     gtk_object_set_data(GTK_OBJECT(holder), "desktop", desktop);
1754     gchar const * descr =
1755         "<ui>"
1756         "  <toolbar name='RectToolbar'>"
1757         "    <toolitem action='RectStateAction' />"
1758         "    <toolitem action='WidthAction' />"
1759         "    <toolitem action='HeightAction' />"
1760         "    <toolitem action='RadiusXAction' />"
1761         "    <toolitem action='RadiusYAction' />"
1762         "    <toolitem action='RectUnitsAction' />"
1763         "    <separator />"
1764         "    <toolitem action='RectResetAction' />"
1765         "  </toolbar>"
1766         "</ui>";
1767     GtkActionGroup* mainActions = gtk_action_group_new("main");
1769     EgeAdjustmentAction* eact = 0;
1771     {
1772         EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
1773         ege_output_action_set_use_markup( act, TRUE );
1774         gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1775         gtk_object_set_data( GTK_OBJECT(holder), "mode_action", act );
1776     }
1778     // rx/ry units menu: create
1779     UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1780     //tracker->addUnit( SP_UNIT_PERCENT, 0 );
1781     // fixme: add % meaning per cent of the width/height
1782     tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1783     gtk_object_set_data( GTK_OBJECT(holder), "tracker", tracker );
1785     /* W */
1786     {
1787         eact = create_adjustment_action( "WidthAction",
1788                                          _("W:"), _("Width of rectangle"),
1789                                          "tools.shapes.rect", "width", 0,
1790                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
1791                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1792                                          0, 0, 0,
1793                                          sp_rtb_width_value_changed );
1794         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1795         gtk_object_set_data( GTK_OBJECT(holder), "width_action", eact );
1796         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1797         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1798     }
1800     /* H */
1801     {
1802         eact = create_adjustment_action( "HeightAction",
1803                                          _("H:"), _("Height of rectangle"),
1804                                          "tools.shapes.rect", "height", 0,
1805                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1806                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1807                                          0, 0, 0,
1808                                          sp_rtb_height_value_changed );
1809         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1810         gtk_object_set_data( GTK_OBJECT(holder), "height_action", eact );
1811         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1812         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1813     }
1815     /* rx */
1816     {
1817         eact = create_adjustment_action( "RadiusXAction",
1818                                          _("Rx:"), _("Horizontal radius of rounded corners"),
1819                                          "tools.shapes.rect", "rx", 0,
1820                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1821                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1822                                          0, 0, 0,
1823                                          sp_rtb_rx_value_changed);
1824         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1825         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1826     }
1828     /* ry */
1829     {
1830         eact = create_adjustment_action( "RadiusYAction",
1831                                          _("Ry:"), _("Vertical radius of rounded corners"),
1832                                          "tools.shapes.rect", "ry", 0,
1833                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1834                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1835                                          0, 0, 0,
1836                                          sp_rtb_ry_value_changed);
1837         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1838         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1839     }
1841     // add the units menu
1842     {
1843         GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), _("") );
1844         gtk_action_group_add_action( mainActions, act );
1845     }
1847     /* Reset */
1848     {
1849         InkAction* inky = ink_action_new( "RectResetAction",
1850                                           _("Not rounded"),
1851                                           _("Make corners sharp"),
1852                                           "squared_corner",
1853                                           Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1854         g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
1855         gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1856         gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
1857         gtk_object_set_data( GTK_OBJECT(holder), "not_rounded", inky );
1858     }
1860     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new rectangles"));
1861     swatch->setDesktop (desktop);
1862     swatch->setClickVerb (SP_VERB_CONTEXT_RECT_PREFS);
1863     swatch->setWatchedTool ("tools.shapes.rect", true);
1864     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1865     gtk_box_pack_end(GTK_BOX(holder), swatch_, FALSE, FALSE, 0);
1867     g_object_set_data(G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE));
1868     sp_rtb_sensitivize (holder);
1871     GtkUIManager* mgr = gtk_ui_manager_new();
1872     GError* errVal = 0;
1874     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1875     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1877     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/RectToolbar" );
1878     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1879     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
1882     gtk_box_pack_start( GTK_BOX(holder), toolBar, TRUE, TRUE, 0 );
1885     gtk_widget_show_all(holder);
1886     sp_set_font_size_smaller(holder);
1888     sigc::connection *connection = new sigc::connection(
1889         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)holder))
1890         );
1891     g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(delete_connection), connection);
1893     return holder;
1896 //########################
1897 //##       Spiral       ##
1898 //########################
1900 static void
1901 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1903     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1905     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1906         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1907     }
1909     // quit if run by the attr_changed listener
1910     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1911         return;
1912     }
1914     // in turn, prevent listener from responding
1915     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1917     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1919     bool modmade = false;
1920     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1921          items != NULL;
1922          items = items->next)
1923     {
1924         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1925             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1926             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1927             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1928             modmade = true;
1929         }
1930     }
1932     g_free(namespaced_name);
1934     if (modmade) {
1935         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
1936                                    _("Change spiral"));
1937     }
1939     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1941     spinbutton_defocus(GTK_OBJECT(tbl));
1944 static void
1945 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1947     sp_spl_tb_value_changed(adj, tbl, "revolution");
1950 static void
1951 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1953     sp_spl_tb_value_changed(adj, tbl, "expansion");
1956 static void
1957 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1959     sp_spl_tb_value_changed(adj, tbl, "t0");
1962 static void
1963 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1965     GtkWidget *tbl = GTK_WIDGET(obj);
1967     GtkAdjustment *adj;
1969     // fixme: make settable
1970     gdouble rev = 5;
1971     gdouble exp = 1.0;
1972     gdouble t0 = 0.0;
1974     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1975     gtk_adjustment_set_value(adj, rev);
1976     gtk_adjustment_value_changed(adj);
1978     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1979     gtk_adjustment_set_value(adj, exp);
1980     gtk_adjustment_value_changed(adj);
1982     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1983     gtk_adjustment_set_value(adj, t0);
1984     gtk_adjustment_value_changed(adj);
1986     spinbutton_defocus(GTK_OBJECT(tbl));
1990 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1991                                          gchar const *old_value, gchar const *new_value,
1992                                          bool is_interactive, gpointer data)
1994     GtkWidget *tbl = GTK_WIDGET(data);
1996     // quit if run by the _changed callbacks
1997     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1998         return;
1999     }
2001     // in turn, prevent callbacks from responding
2002     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2004     GtkAdjustment *adj;
2005     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2006     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2008     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2009     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2011     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2012     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2014     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2018 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2019     NULL, /* child_added */
2020     NULL, /* child_removed */
2021     spiral_tb_event_attr_changed,
2022     NULL, /* content_changed */
2023     NULL  /* order_changed */
2024 };
2026 static void
2027 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2029     int n_selected = 0;
2030     Inkscape::XML::Node *repr = NULL;
2031     Inkscape::XML::Node *oldrepr = NULL;
2033     for (GSList const *items = selection->itemList();
2034          items != NULL;
2035          items = items->next)
2036     {
2037         if (SP_IS_SPIRAL((SPItem *) items->data)) {
2038             n_selected++;
2039             repr = SP_OBJECT_REPR((SPItem *) items->data);
2040         }
2041     }
2043     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2045     if (n_selected == 0) {
2046         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2047     } else if (n_selected == 1) {
2048         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2050         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2051         if (oldrepr) { // remove old listener
2052             sp_repr_remove_listener_by_data(oldrepr, tbl);
2053             Inkscape::GC::release(oldrepr);
2054             oldrepr = 0;
2055             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2056         }
2058         if (repr) {
2059             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2060             Inkscape::GC::anchor(repr);
2061             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2062             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2063         }
2064     } else {
2065         // FIXME: implement averaging of all parameters for multiple selected
2066         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2067         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2068     }
2072 static GtkWidget *
2073 sp_spiral_toolbox_new(SPDesktop *desktop)
2075     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2076     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2077     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2079     GtkTooltips *tt = gtk_tooltips_new();
2081     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2083     /* Revolution */
2084     {
2085         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
2086                                          "tools.shapes.spiral", "revolution", 3.0,
2087                                          NULL, tbl, TRUE, "altx-spiral",
2088                                          0.01, 1024.0, 0.1, 1.0,
2089                                          sp_spl_tb_revolution_value_changed, 1, 2);
2090         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2091     }
2093     /* Expansion */
2094     {
2095         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2096                                          "tools.shapes.spiral", "expansion", 1.0,
2097                                          NULL, tbl, FALSE, NULL,
2098                                          0.0, 1000.0, 0.01, 1.0,
2099                                          sp_spl_tb_expansion_value_changed);
2100         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2101     }
2103     /* T0 */
2104     {
2105         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2106                                          "tools.shapes.spiral", "t0", 0.0,
2107                                          NULL, tbl, FALSE, NULL,
2108                                          0.0, 0.999, 0.01, 1.0,
2109                                          sp_spl_tb_t0_value_changed);
2110         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2111     }
2113     aux_toolbox_space(tbl, AUX_SPACING);
2115     /* Reset */
2116     {
2117         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2118         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2119         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2120         gtk_widget_show(b);
2121         gtk_container_add(GTK_CONTAINER(hb), b);
2122         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
2123         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2124     }
2126     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new spirals"));
2127     swatch->setDesktop (desktop);
2128     swatch->setClickVerb (SP_VERB_CONTEXT_SPIRAL_PREFS);
2129     swatch->setWatchedTool ("tools.shapes.spiral", true);
2130     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2131     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2133     gtk_widget_show_all(tbl);
2134     sp_set_font_size_smaller (tbl);
2136     sigc::connection *connection = new sigc::connection(
2137         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
2138         );
2139     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2141     return tbl;
2144 //########################
2145 //##     Pen/Pencil    ##
2146 //########################
2149 static GtkWidget *
2150 sp_pen_toolbox_new(SPDesktop *desktop)
2152     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2153     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2154     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2156     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new paths created by Pen"));
2157     swatch->setDesktop (desktop);
2158     swatch->setClickVerb (SP_VERB_CONTEXT_PEN_PREFS);
2159     swatch->setWatchedTool ("tools.freehand.pen", true);
2160     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2161     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2163     gtk_widget_show_all(tbl);
2164     sp_set_font_size_smaller (tbl);
2166     return tbl;
2169 static GtkWidget *
2170 sp_pencil_toolbox_new(SPDesktop *desktop)
2172     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2173     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2174     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2176     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new paths created by Pencil"));
2177     swatch->setDesktop (desktop);
2178     swatch->setClickVerb (SP_VERB_CONTEXT_PENCIL_PREFS);
2179     swatch->setWatchedTool ("tools.freehand.pencil", true);
2180     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2181     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2183     gtk_widget_show_all(tbl);
2184     sp_set_font_size_smaller (tbl);
2186     return tbl;
2190 //########################
2191 //##     Calligraphy    ##
2192 //########################
2194 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2196     prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
2199 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2201     prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
2204 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2206     prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
2209 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2211     prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
2214 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2216     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
2219 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2221     prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
2224 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2226     prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
2229 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2231     prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
2234 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer data )
2236     prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2239 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer data )
2241     prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
2244 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
2246     prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2248     gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
2251 static void sp_ddc_defaults(GtkWidget *, GtkWidget *dataKludge)
2253     // FIXME: make defaults settable via Inkscape Options
2254     struct KeyValue {
2255         char const *key;
2256         double value;
2257     } const key_values[] = {
2258         {"mass", 0.02},
2259         {"wiggle", 0.0},
2260         {"angle", 30.0},
2261         {"width", 15},
2262         {"thinning", 0.1},
2263         {"tremor", 0.0},
2264         {"flatness", 0.9},
2265         {"cap_rounding", 0.0}
2266     };
2268     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2269         KeyValue const &kv = key_values[i];
2270         GtkAdjustment* adj = static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(dataKludge), kv.key));
2271         if ( adj ) {
2272             gtk_adjustment_set_value(adj, kv.value);
2273         }
2274     }
2278 static GtkWidget *
2279 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2281     GtkWidget* holder = gtk_table_new( 1, 2, FALSE );
2283     gchar const * descr =
2284         "<ui>"
2285         "  <toolbar name='CalligraphyToolbar'>"
2286         "    <separator />"
2287         "    <toolitem name='Width' action='WidthAction' />"
2288         "    <toolitem name='Thinning' action='ThinningAction' />"
2289         "    <separator />"
2290         "    <toolitem name='Angle' action='AngleAction' />"
2291         "    <toolitem action='FixationAction' />"
2292         "    <toolitem action='CapRoundingAction' />"
2293         "    <separator />"
2294         "    <toolitem action='TremorAction' />"
2295         "    <toolitem action='WiggleAction' />"
2296         "    <toolitem action='MassAction' />"
2297         "    <separator />"
2298         "    <toolitem action='TraceAction' />"
2299         "    <toolitem action='PressureAction' />"
2300         "    <toolitem action='TiltAction' />"
2301         "    <toolitem action='ResetAction' />"
2302         "  </toolbar>"
2303         "</ui>";
2304     GtkActionGroup* mainActions = gtk_action_group_new("main");
2306     {
2307         EgeAdjustmentAction* calligraphy_angle = 0;
2309         {
2310         /* Width */
2311         gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
2312         gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2313         EgeAdjustmentAction *eact = create_adjustment_action( "WidthAction",
2314                                          _("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2315                                          "tools.calligraphic", "width", 15,
2316                                          GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
2317                                          1, 100, 1.0, 10.0,
2318                                          labels, values, G_N_ELEMENTS(labels),
2319                                          sp_ddc_width_value_changed,  0.01, 0, 100 );
2320         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2321         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2322         }
2324         {
2325         /* Thinning */
2326             gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
2327             gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
2328         EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
2329                                          _("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2330                                          "tools.calligraphic", "thinning", 0.1,
2331                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2332                                          -1.0, 1.0, 0.01, 0.1,
2333                                          labels, values, G_N_ELEMENTS(labels),
2334                                          sp_ddc_velthin_value_changed, 0.01, 2);
2335         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2336         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2337         }
2339         {
2340         /* Angle */
2341         gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
2342         gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2343         EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
2344                                          _("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2345                                          "tools.calligraphic", "angle", 30,
2346                                          GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
2347                                          -90.0, 90.0, 1.0, 10.0,
2348                                          labels, values, G_N_ELEMENTS(labels),
2349                                          sp_ddc_angle_value_changed, 1, 0 );
2350         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2351         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2352         calligraphy_angle = eact;
2353         }
2355         {
2356         /* Fixation */
2357             gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
2358         gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
2359         EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
2360                                          _("Fixation:"), _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
2361                                          "tools.calligraphic", "flatness", 0.9,
2362                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2363                                          0.0, 1.0, 0.01, 0.1,
2364                                          labels, values, G_N_ELEMENTS(labels),
2365                                          sp_ddc_flatness_value_changed, 0.01, 2 );
2366         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2367         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2368         }
2370         {
2371         /* Cap Rounding */
2372             gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
2373         gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
2374         // TRANSLATORS: "cap" means "end" (both start and finish) here
2375         EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
2376                                          _("Caps:"), _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
2377                                          "tools.calligraphic", "cap_rounding", 0.0,
2378                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2379                                          0.0, 5.0, 0.01, 0.1,
2380                                          labels, values, G_N_ELEMENTS(labels),
2381                                          sp_ddc_cap_rounding_value_changed, 0.01, 2 );
2382         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2383         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2384         }
2386         {
2387         /* Tremor */
2388             gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
2389         gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
2390         EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
2391                                          _("Tremor:"), _("Increase to make strokes rugged and trembling"),
2392                                          "tools.calligraphic", "tremor", 0.0,
2393                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2394                                          0.0, 1.0, 0.01, 0.1,
2395                                          labels, values, G_N_ELEMENTS(labels),
2396                                          sp_ddc_tremor_value_changed, 0.01, 2 );
2398         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2399         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2400         }
2402         {
2403         /* Wiggle */
2404         gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
2405         gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
2406         EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
2407                                          _("Wiggle:"), _("Increase to make the pen waver and wiggle"),
2408                                          "tools.calligraphic", "wiggle", 0.0,
2409                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2410                                          0.0, 1.0, 0.01, 0.1,
2411                                          labels, values, G_N_ELEMENTS(labels),
2412                                          sp_ddc_wiggle_value_changed, 0.01, 2 );
2413         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2414         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2415         }
2417         {
2418         /* Mass */
2419             gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
2420         gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
2421         EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
2422                                          _("Mass:"), _("Increase to make the pen drag behind, as if slowed by inertia"),
2423                                          "tools.calligraphic", "mass", 0.02,
2424                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2425                                          0.0, 1.0, 0.01, 0.1,
2426                                          labels, values, G_N_ELEMENTS(labels),
2427                                          sp_ddc_mass_value_changed, 0.01, 2 );
2428         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2429         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2430         }
2433         /* Trace Background button */
2434         {
2435             InkToggleAction* act = ink_toggle_action_new( "TraceAction",
2436                                                           _("Trace Background"),
2437                                                           _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
2438                                                           "trace_background",
2439                                                           Inkscape::ICON_SIZE_DECORATION );
2440             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2441             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
2442             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
2443         }
2445         /* Use Pressure button */
2446         {
2447             InkToggleAction* act = ink_toggle_action_new( "PressureAction",
2448                                                           _("Pressure"),
2449                                                           _("Use the pressure of the input device to alter the width of the pen"),
2450                                                           "use_pressure",
2451                                                           Inkscape::ICON_SIZE_DECORATION );
2452             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2453             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
2454             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
2455         }
2457         /* Use Tilt button */
2458         {
2459             InkToggleAction* act = ink_toggle_action_new( "TiltAction",
2460                                                           _("Tilt"),
2461                                                           _("Use the tilt of the input device to alter the angle of the pen's nib"),
2462                                                           "use_tilt",
2463                                                           Inkscape::ICON_SIZE_DECORATION );
2464             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2465             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
2466             gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2467             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2468         }
2470         /* Reset */
2471         {
2472             GtkAction* act = gtk_action_new( "ResetAction",
2473                                              _("Defaults"),
2474                                              _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2475                                              GTK_STOCK_CLEAR );
2476             g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
2477             gtk_action_group_add_action( mainActions, act );
2478             gtk_action_set_sensitive( act, TRUE );
2479         }
2480     }
2483     GtkUIManager* mgr = gtk_ui_manager_new();
2484     GError* errVal = 0;
2486     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
2487     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
2489     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CalligraphyToolbar" );
2490     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
2491     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
2494     gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
2496     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new calligraphic strokes"));
2497     swatch->setDesktop (desktop);
2498     swatch->setClickVerb (SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS);
2499     swatch->setWatchedTool ("tools.calligraphic", true);
2500     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2501     gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, 0 );
2503     gtk_widget_show_all(holder);
2504     //sp_set_font_size_smaller (tbl);
2506     return holder;
2510 //########################
2511 //##    Circle / Arc    ##
2512 //########################
2514 static void
2515 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2517     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2518     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2520     if (v1 == 0 && v2 == 0) {
2521         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2522             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2523             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2524         }
2525     } else {
2526         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2527         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2528     }
2531 static void
2532 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2534     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2536     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2537         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2538     }
2540     // quit if run by the attr_changed listener
2541     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2542         return;
2543     }
2545     // in turn, prevent listener from responding
2546     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2548     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2550     bool modmade = false;
2551     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2552          items != NULL;
2553          items = items->next)
2554     {
2555         SPItem *item = SP_ITEM(items->data);
2557         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2559             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2560             SPArc *arc = SP_ARC(item);
2562             if (!strcmp(value_name, "start"))
2563                 ge->start = (adj->value * M_PI)/ 180;
2564             else
2565                 ge->end = (adj->value * M_PI)/ 180;
2567             sp_genericellipse_normalize(ge);
2568             ((SPObject *)arc)->updateRepr();
2569             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2571             modmade = true;
2572         }
2573     }
2575     g_free(namespaced_name);
2577     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2579     sp_arctb_sensitivize (tbl, adj->value, other->value);
2581     if (modmade) {
2582         sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
2583                                    _("Arc: Change start/end"));
2584     }
2586     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2587     spinbutton_defocus(GTK_OBJECT(tbl));
2589     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2593 static void
2594 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2596     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2599 static void
2600 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2602     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2605 static void
2606 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2608     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2610     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2611         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2612             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2613         } else {
2614             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2615         }
2616     }
2618     // quit if run by the attr_changed listener
2619     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2620         return;
2621     }
2623     // in turn, prevent listener from responding
2624     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2626     bool modmade = false;
2628     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2629         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2630              items != NULL;
2631              items = items->next)
2632         {
2633             if (SP_IS_ARC((SPItem *) items->data)) {
2634                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2635                 repr->setAttribute("sodipodi:open", "true");
2636                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2637                 modmade = true;
2638             }
2639         }
2640     } else {
2641         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2642              items != NULL;
2643              items = items->next)
2644         {
2645             if (SP_IS_ARC((SPItem *) items->data))    {
2646                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2647                 repr->setAttribute("sodipodi:open", NULL);
2648                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2649                 modmade = true;
2650             }
2651         }
2652     }
2654     if (modmade) {
2655         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
2656                                    _("Arc: Change open/closed"));
2657     }
2659     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2661     spinbutton_defocus(GTK_OBJECT(tbl));
2664 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2666     GtkWidget *tbl = GTK_WIDGET(obj);
2668     GtkAdjustment *adj;
2669     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2670     gtk_adjustment_set_value(adj, 0.0);
2671     gtk_adjustment_value_changed(adj);
2673     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2674     gtk_adjustment_set_value(adj, 0.0);
2675     gtk_adjustment_value_changed(adj);
2677     spinbutton_defocus(GTK_OBJECT(tbl));
2680 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2681                                       gchar const *old_value, gchar const *new_value,
2682                                       bool is_interactive, gpointer data)
2684     GtkWidget *tbl = GTK_WIDGET(data);
2686     // quit if run by the _changed callbacks
2687     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2688         return;
2689     }
2691     // in turn, prevent callbacks from responding
2692     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2694     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2695     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2697     GtkAdjustment *adj1,*adj2;
2698     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2699     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2700     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2701     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2703     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2705     char const *openstr = NULL;
2706     openstr = repr->attribute("sodipodi:open");
2707     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2709     if (openstr) {
2710         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2711     } else {
2712         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2713     }
2715     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2718 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2719     NULL, /* child_added */
2720     NULL, /* child_removed */
2721     arc_tb_event_attr_changed,
2722     NULL, /* content_changed */
2723     NULL  /* order_changed */
2724 };
2727 static void
2728 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2730     int n_selected = 0;
2731     Inkscape::XML::Node *repr = NULL;
2732     Inkscape::XML::Node *oldrepr = NULL;
2734     for (GSList const *items = selection->itemList();
2735          items != NULL;
2736          items = items->next)
2737     {
2738         if (SP_IS_ARC((SPItem *) items->data)) {
2739             n_selected++;
2740             repr = SP_OBJECT_REPR((SPItem *) items->data);
2741         }
2742     }
2744     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2746     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2747     if (n_selected == 0) {
2748         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2749     } else if (n_selected == 1) {
2750         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2751         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2753         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2755         if (oldrepr) { // remove old listener
2756             sp_repr_remove_listener_by_data(oldrepr, tbl);
2757             Inkscape::GC::release(oldrepr);
2758             oldrepr = 0;
2759             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2760         }
2762         if (repr) {
2763             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2764             Inkscape::GC::anchor(repr);
2765             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2766             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2767         }
2768     } else {
2769         // FIXME: implement averaging of all parameters for multiple selected
2770         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2771         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2772         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2773     }
2777 static GtkWidget *
2778 sp_arc_toolbox_new(SPDesktop *desktop)
2780     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2782     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2783     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2785     GtkTooltips *tt = gtk_tooltips_new();
2787     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2789     /* Start */
2790     {
2791         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2792                                          "tools.shapes.arc", "start", 0.0,
2793                                          NULL, tbl, TRUE, "altx-arc",
2794                                          -360.0, 360.0, 1.0, 10.0,
2795                                          sp_arctb_start_value_changed);
2796         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2797     }
2799     /* End */
2800     {
2801         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2802                                          "tools.shapes.arc", "end", 0.0,
2803                                          NULL, tbl, FALSE, NULL,
2804                                          -360.0, 360.0, 1.0, 10.0,
2805                                          sp_arctb_end_value_changed);
2806         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2807     }
2809     /* Segments / Pie checkbox */
2810     {
2811         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2812         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2813         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2815         gchar const *openstr = NULL;
2816         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2817         if (!openstr || (openstr && !strcmp(openstr, "false")))
2818             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2819         else
2820             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2822         gtk_widget_show(fscb);
2823         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2824         gtk_container_add(GTK_CONTAINER(hb), fscb);
2825         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2826         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2827     }
2829     /* Make Whole */
2830     {
2831         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2832         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2833         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2834         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2835         gtk_widget_show(b);
2836         gtk_container_add(GTK_CONTAINER(hb), b);
2837         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2838         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2839     }
2841     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2842     // sensitivize make whole and open checkbox
2843     {
2844         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2845         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2846         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2847     }
2849     sigc::connection *connection = new sigc::connection(
2850         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2851         );
2852     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2854     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new ellipses"));
2855     swatch->setDesktop (desktop);
2856     swatch->setClickVerb (SP_VERB_CONTEXT_ARC_PREFS);
2857     swatch->setWatchedTool ("tools.shapes.arc", true);
2858     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2859     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2861     gtk_widget_show_all(tbl);
2862     sp_set_font_size_smaller (tbl);
2864     return tbl;
2870 // toggle button callbacks and updaters
2872 //########################
2873 //##      Dropper       ##
2874 //########################
2876 static void toggle_dropper_pick_alpha (GtkWidget *button, gpointer tbl) {
2877     prefs_set_int_attribute ("tools.dropper", "pick",
2878         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
2879     GtkWidget *set_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "set_checkbox");
2880     if (set_checkbox) {
2881         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
2882             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), TRUE);
2883         } else {
2884             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), FALSE);
2885         }
2886     }
2887     spinbutton_defocus(GTK_OBJECT(tbl));
2890 static void toggle_dropper_set_alpha (GtkWidget *button, gpointer tbl) {
2891     prefs_set_int_attribute ("tools.dropper", "setalpha",
2892         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
2893     spinbutton_defocus(GTK_OBJECT(tbl));
2897 /**
2898  * Copy the current saved desktop color to the clipboard as full hex + alpha
2899  * color representation. This is useful for passing values between various
2900  * input boxes, or directly to xml.
2901  */
2902 /* static void
2903 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2905     GtkWidget *tbl = GTK_WIDGET(obj);
2907     SPDesktop *desktop =
2908         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2911     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2912 }*/
2915 /**
2916  * Copies currently saved desktop color to the clipboard as a hex value. This
2917  * is useful for editing webpages and needing a value quickly for web
2918  * colors.
2919  *
2920  * TODO: When the toggle of the dropper is set to not mix color against
2921  *       page background, this still just gets the color of the page and
2922  *       doesn't get the actual mixed against background which is needed
2923  *       for the hex value ppl. want for web pages, etc.
2924  */
2926 /* static void
2927 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2929     GtkWidget *tbl = GTK_WIDGET(obj);
2931     SPDesktop *desktop =
2932         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2934     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2935 }*/
2938 /**
2939  * Sets the input boxes with the changed color and opacity. This is used as a
2940  * callback for style changing.
2941  */
2942 /* static bool
2943 sp_style_changed (const SPCSSAttr *css, gpointer data)
2945     // GrDrag *drag = (GrDrag *) data;
2947     // set fill of text entry box
2948     if (css->attribute("fill"))
2949         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2950             css->attribute("fill"));
2952     // set opacity of text entry box
2953     if (css->attribute("fill-opacity"))
2954         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2955             css->attribute("fill-opacity"));
2957     // set fill of text entry box
2958     if (css->attribute("stroke"))
2959         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2960             css->attribute("stroke"));
2962     // set opacity of text entry box
2963     if (css->attribute("stroke-opacity"))
2964         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2965             css->attribute("stroke-opacity"));
2966     return false;
2969 */
2972 /**
2973  * Dropper auxiliary toolbar construction and setup.
2974  *
2975  * TODO: Would like to add swatch of current color.
2976  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2977  *       can drag and drop places. Will provide a nice mixing palette.
2978  */
2979 static GtkWidget *
2980 sp_dropper_toolbox_new(SPDesktop *desktop)
2982     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2984     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2985     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2987     GtkTooltips *tt = gtk_tooltips_new();
2990     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
2991                        AUX_BETWEEN_BUTTON_GROUPS);
2992     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2996     /* RGB Input Field */
2997  /*   {
2998         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2999         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
3000         gtk_widget_show (dropper_rgba_label);
3001         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
3003         dropper_rgb_entry = gtk_entry_new ();
3004         sp_dialog_defocus_on_enter (dropper_rgb_entry);
3005         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
3006         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
3007         gtk_tooltips_set_tip(tt, dropper_rgb_entry,
3008                          _("Hexidecimal representation of last selected "
3009                            "color"),
3010                          NULL);
3011         gtk_widget_show (dropper_rgb_entry);
3012         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
3014         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3015                            AUX_BETWEEN_BUTTON_GROUPS);
3016     } */
3018     /* Opacity Input Field */
3019 /*    {
3020         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3021         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
3022         gtk_widget_show (dropper_opacity_label);
3023         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
3025         dropper_opacity_entry = gtk_entry_new ();
3026         sp_dialog_defocus_on_enter (dropper_opacity_entry);
3027         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
3028         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
3029         gtk_tooltips_set_tip(tt, dropper_opacity_entry,
3030                          _("Opacity of last selected color"),
3031                          NULL);
3032         gtk_widget_show (dropper_opacity_entry);
3033         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
3035         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3036                            AUX_BETWEEN_BUTTON_GROUPS);
3037     } */
3040     /* Copy to Clipboard */
3041 /*    {
3042         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3043         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
3044         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
3045                                       "RGB + Alpha (RGBA) to "
3046                                       "clipboard"),
3047                              NULL);
3048         gtk_widget_show(b);
3049         gtk_container_add(GTK_CONTAINER(hb), b);
3050         gtk_signal_connect(GTK_OBJECT(b), "clicked",
3051             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
3052         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3053                            AUX_BETWEEN_BUTTON_GROUPS);
3054     } */
3057     /* Copy to Clipboard as HEX */
3058 /*    {
3059         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3060         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
3061         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
3062                                       "hexidecimal RGB without alpha "
3063                                       "to clipboard"), NULL);
3064         gtk_widget_show(b);
3065         gtk_container_add(GTK_CONTAINER(hb), b);
3066         gtk_signal_connect(GTK_OBJECT(b), "clicked",
3067             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
3068         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3069                            AUX_BETWEEN_BUTTON_GROUPS);
3070     } */
3072     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3074     {
3075         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3077         GtkWidget *button = gtk_check_button_new_with_label(_("Pick alpha"));
3078         gtk_tooltips_set_tip(tt, button, _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"), NULL);
3079         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
3080                                       prefs_get_int_attribute ("tools.dropper",
3081                                                                "pick", 1));
3082         gtk_widget_show(button);
3083         gtk_container_add (GTK_CONTAINER (hb), button);
3084         gtk_object_set_data(GTK_OBJECT(tbl), "pick_checkbox", button);
3085         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_pick_alpha), tbl);
3086         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3087                    AUX_BETWEEN_BUTTON_GROUPS);
3088     }
3090     {
3091         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3093         GtkWidget *button = gtk_check_button_new_with_label(_("Set alpha"));
3094         gtk_tooltips_set_tip(tt, button, _("If alpha was picked, assign it to selection as fill or stroke transparency"), NULL);
3095         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
3096                                       prefs_get_int_attribute ("tools.dropper",
3097                                                                "setalpha", 1));
3098         gtk_widget_show(button);
3099         gtk_container_add (GTK_CONTAINER (hb), button);
3100         gtk_object_set_data(GTK_OBJECT(tbl), "set_checkbox", button);
3101         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_set_alpha), tbl);
3103         // make sure it's disabled if we're not picking alpha
3104         GtkWidget *pick_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "pick_checkbox");
3105         if (pick_checkbox) {
3106             if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pick_checkbox))) {
3107                 gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
3108             } else {
3109                 gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
3110             }
3111         }
3113         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3114                    AUX_BETWEEN_BUTTON_GROUPS);
3115     }
3117     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3120     // where new gtkmm stuff should go
3122     gtk_widget_show_all(tbl);
3123     sp_set_font_size_smaller (tbl);
3125     /*
3126     sigc::connection *connection = new sigc::connection(
3127         desktop->connectSetStyle(
3128             sigc::bind(sigc::ptr_fun(sp_style_changed),
3129                        desktop)) );
3131     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection),
3132                      connection); */
3134     return tbl;
3138 //########################
3139 //##    Text Toolbox    ##
3140 //########################
3141 /*
3142 static void
3143 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3145     //Call back for letter sizing spinbutton
3148 static void
3149 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3151     //Call back for line height spinbutton
3154 static void
3155 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3157     //Call back for horizontal kerning spinbutton
3160 static void
3161 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3163     //Call back for vertical kerning spinbutton
3166 static void
3167 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3169     //Call back for letter rotation spinbutton
3170 }*/
3172 namespace {
3174 bool visible = false;
3176 void
3177 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
3180     SPStyle *query =
3181         sp_style_new ();
3183     int result_family =
3184         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3186     int result_style =
3187         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3189     int result_numbers =
3190         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3192     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3194     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3195     if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3196     {
3197         Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3199         if (repr)
3200         {
3201             sp_style_read_from_repr (query, repr);
3202         }
3203         else
3204         {
3205             return;
3206         }
3207     }
3209     if (query->text)
3210     {
3211         if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3212             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3213             gtk_entry_set_text (GTK_ENTRY (entry), "");
3215         } else if (query->text->font_family.value) {
3217             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3218             gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3220             Gtk::TreePath path;
3221             try {
3222                 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3223             } catch (...) {
3224                 return;
3225             }
3227             GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3228             GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3230             g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3232             gtk_tree_selection_select_path (tselection, path.gobj());
3233             gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3235             g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3236         }
3238         //Size
3239         GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3240         char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3241         g_object_set_data (tbl, "size-block", gpointer(1));
3242         gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3243         g_object_set_data (tbl, "size-block", gpointer(0));
3244         free (str);
3246         //Anchor
3247         if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3248         {
3249             GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3250             g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3251             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3252             g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3253         }
3254         else
3255         {
3256             if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3257             {
3258                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3259                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3260                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3261                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3262             }
3263             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3264             {
3265                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3266                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3267                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3268                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3269             }
3270             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3271             {
3272                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3273                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3274                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3275                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3276             }
3277         }
3279         //Style
3280         {
3281             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3283             gboolean active = gtk_toggle_button_get_active (button);
3284             gboolean check  = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3286             if (active != check)
3287             {
3288                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3289                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3290                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3291             }
3292         }
3294         {
3295             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3297             gboolean active = gtk_toggle_button_get_active (button);
3298             gboolean check  = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3300             if (active != check)
3301             {
3302                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3303                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3304                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3305             }
3306         }
3308         //Orientation
3309         //locking both buttons, changing one affect all group (both)
3310         GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3311         g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3313         GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3314         g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3316         if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3317         {
3318             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3319         }
3320         else
3321         {
3322             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3323         }
3324         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3325         g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3326     }
3329 void
3330 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
3332     sp_text_toolbox_selection_changed (selection, tbl);
3335 void
3336 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3338     sp_text_toolbox_selection_changed (NULL, tbl);
3341 void
3342 sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
3343                                 GObject             *tbl)
3345     SPDesktop    *desktop = SP_ACTIVE_DESKTOP;
3346     GtkTreeModel *model = 0;
3347     GtkWidget    *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3348     GtkWidget    *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3349     GtkTreeIter   iter;
3350     char         *family = 0;
3352     gdk_pointer_ungrab (GDK_CURRENT_TIME);
3353     gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3355     if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3356         return;
3357     }
3359     gtk_tree_model_get (model, &iter, 0, &family, -1);
3361     if (g_object_get_data (G_OBJECT (selection), "block"))
3362     {
3363         gtk_entry_set_text (GTK_ENTRY (entry), family);
3364         return;
3365     }
3367     gtk_widget_hide (popdown);
3368     visible = false;
3370     gtk_entry_set_text (GTK_ENTRY (entry), family);
3372     SPStyle *query =
3373         sp_style_new ();
3375     int result_numbers =
3376         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3378     SPCSSAttr *css = sp_repr_css_attr_new ();
3379     sp_repr_css_set_property (css, "font-family", family);
3381     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3382     if (result_numbers == QUERY_STYLE_NOTHING)
3383     {
3384         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3385         sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3386     }
3387     else
3388     {
3389         sp_desktop_set_style (desktop, css, true, true);
3390     }
3392     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3393                                    _("Text: Change font family"));
3394     sp_repr_css_attr_unref (css);
3395     free (family);
3396     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3398     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3401 void
3402 sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
3403                                        GObject      *tbl)
3405     const char *family = gtk_entry_get_text (entry);
3407     try {
3408         Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3409         GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3410         GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3411         gtk_tree_selection_select_path (selection, path.gobj());
3412         gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3413         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3414     } catch (...) {
3415         if (family && strlen (family))
3416         {
3417             gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3418         }
3419     }
3422 void
3423 sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
3424                                    gpointer          data)
3426     if (g_object_get_data (G_OBJECT (button), "block")) return;
3427     if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3428     int prop = GPOINTER_TO_INT(data);
3430     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3431     SPCSSAttr *css = sp_repr_css_attr_new ();
3433     switch (prop)
3434     {
3435         case 0:
3436         {
3437             sp_repr_css_set_property (css, "text-anchor", "start");
3438             sp_repr_css_set_property (css, "text-align", "start");
3439             break;
3440         }
3441         case 1:
3442         {
3443             sp_repr_css_set_property (css, "text-anchor", "middle");
3444             sp_repr_css_set_property (css, "text-align", "center");
3445             break;
3446         }
3448         case 2:
3449         {
3450             sp_repr_css_set_property (css, "text-anchor", "end");
3451             sp_repr_css_set_property (css, "text-align", "end");
3452             break;
3453         }
3455         case 3:
3456         {
3457             sp_repr_css_set_property (css, "text-anchor", "start");
3458             sp_repr_css_set_property (css, "text-align", "justify");
3459             break;
3460         }
3461     }
3463     SPStyle *query =
3464         sp_style_new ();
3465     int result_numbers =
3466         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3468     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3469     if (result_numbers == QUERY_STYLE_NOTHING)
3470     {
3471         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3472     }
3474     sp_desktop_set_style (desktop, css, true, true);
3475     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3476                                    _("Text: Change alignment"));
3477     sp_repr_css_attr_unref (css);
3479     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3482 void
3483 sp_text_toolbox_style_toggled (GtkToggleButton  *button,
3484                                gpointer          data)
3486     if (g_object_get_data (G_OBJECT (button), "block")) return;
3488     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3489     SPCSSAttr   *css        = sp_repr_css_attr_new ();
3490     int          prop       = GPOINTER_TO_INT(data);
3491     bool         active     = gtk_toggle_button_get_active (button);
3494     switch (prop)
3495     {
3496         case 0:
3497         {
3498             sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
3499             break;
3500         }
3502         case 1:
3503         {
3504             sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
3505             break;
3506         }
3507     }
3509     SPStyle *query =
3510         sp_style_new ();
3511     int result_numbers =
3512         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3514     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3515     if (result_numbers == QUERY_STYLE_NOTHING)
3516     {
3517         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3518     }
3520     sp_desktop_set_style (desktop, css, true, true);
3521     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3522                                    _("Text: Change font style"));
3523     sp_repr_css_attr_unref (css);
3525     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3528 void
3529 sp_text_toolbox_orientation_toggled (GtkRadioButton  *button,
3530                                      gpointer         data)
3532     if (g_object_get_data (G_OBJECT (button), "block")) {
3533         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3534         return;
3535     }
3537     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3538     SPCSSAttr   *css        = sp_repr_css_attr_new ();
3539     int          prop       = GPOINTER_TO_INT(data);
3541     switch (prop)
3542     {
3543         case 0:
3544         {
3545             sp_repr_css_set_property (css, "writing-mode", "lr");
3546             break;
3547         }
3549         case 1:
3550         {
3551             sp_repr_css_set_property (css, "writing-mode", "tb");
3552             break;
3553         }
3554     }
3556     SPStyle *query =
3557         sp_style_new ();
3558     int result_numbers =
3559         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3561     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3562     if (result_numbers == QUERY_STYLE_NOTHING)
3563     {
3564         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3565     }
3567     sp_desktop_set_style (desktop, css, true, true);
3568     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3569                                    _("Text: Change orientation"));
3570     sp_repr_css_attr_unref (css);
3572     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3575 gboolean
3576 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3578     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3579     if (!desktop) return FALSE;
3581     switch (get_group0_keyval (event)) {
3582         case GDK_Escape: // defocus
3583             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3584             return TRUE; // I consumed the event
3585             break;
3586         case GDK_Return: // defocus
3587         case GDK_KP_Enter:
3588             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3589             return TRUE; // I consumed the event
3590             break;
3591     }
3592     return FALSE;
3595 gboolean
3596 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3598     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3599     if (!desktop) return FALSE;
3601     switch (get_group0_keyval (event)) {
3602         case GDK_Escape: // defocus
3603             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3604             sp_text_toolbox_selection_changed (NULL, tbl); // update
3605             return TRUE; // I consumed the event
3606             break;
3607     }
3608     return FALSE;
3611 gboolean
3612 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3614     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3615     if (!desktop) return FALSE;
3617     switch (get_group0_keyval (event)) {
3618         case GDK_Escape: // defocus
3619             gtk_widget_hide (w);
3620             visible = false;
3621             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3622             return TRUE; // I consumed the event
3623             break;
3624     }
3625     return FALSE;
3629 void
3630 sp_text_toolbox_size_changed  (GtkComboBox *cbox,
3631                                GObject     *tbl)
3633     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3635     if (g_object_get_data (tbl, "size-block")) return;
3637 #if GTK_CHECK_VERSION(2,6,0)
3638     char *text = gtk_combo_box_get_active_text (cbox);
3639 #else // GTK_CHECK_VERSION(2,6,0)
3640     GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3641     GtkTreeIter iter;
3642     char *text = NULL;
3644     if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3645         gtk_tree_model_get (model, &iter, 0, &text, -1);
3646 #endif // GTK_CHECK_VERSION(2,6,0)
3648     SPCSSAttr *css = sp_repr_css_attr_new ();
3649     sp_repr_css_set_property (css, "font-size", text);
3650     free (text);
3652     SPStyle *query =
3653         sp_style_new ();
3654     int result_numbers =
3655         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3657     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3658     if (result_numbers == QUERY_STYLE_NOTHING)
3659     {
3660         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3661     }
3663     sp_desktop_set_style (desktop, css, true, true);
3664     sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
3665                                    _("Text: Change font size"));
3666     sp_repr_css_attr_unref (css);
3669     if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3670         gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3673 void
3674 sp_text_toolbox_text_popdown_clicked    (GtkButton          *button,
3675                                          GObject            *tbl)
3677     GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3678     GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3679     int x, y;
3681     if (!visible)
3682     {
3683         gdk_window_get_origin (widget->window, &x, &y);
3684         gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
3685         gtk_widget_show_all (popdown);
3687         gdk_pointer_grab (widget->window, TRUE,
3688                           GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3689                                         GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3690                                         GDK_POINTER_MOTION_MASK),
3691                           NULL, NULL, GDK_CURRENT_TIME);
3693         gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3695         visible = true;
3696     }
3697     else
3698     {
3699         gdk_pointer_ungrab (GDK_CURRENT_TIME);
3700         gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3701         gtk_widget_hide (popdown);
3702         visible = false;
3703     }
3706 gboolean
3707 sp_text_toolbox_entry_focus_in  (GtkWidget        *entry,
3708                                  GdkEventFocus    *event,
3709                                  GObject          *tbl)
3711     gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3712     return FALSE;
3715 gboolean
3716 sp_text_toolbox_popdown_focus_out (GtkWidget        *popdown,
3717                                    GdkEventFocus    *event,
3718                                    GObject          *tbl)
3720     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3722     gtk_widget_hide (popdown);
3723     visible = false;
3724     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3725     return TRUE;
3728 void
3729 cell_data_func  (GtkTreeViewColumn *column,
3730                  GtkCellRenderer   *cell,
3731                  GtkTreeModel      *tree_model,
3732                  GtkTreeIter       *iter,
3733                  gpointer           data)
3735     char        *family,
3736         *family_escaped,
3737         *sample_escaped;
3739     static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3741     gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3743     family_escaped = g_markup_escape_text (family, -1);
3744     sample_escaped = g_markup_escape_text (sample, -1);
3746     std::stringstream markup;
3747     markup << family_escaped << "  <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3748     g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3750     free (family);
3751     free (family_escaped);
3752     free (sample_escaped);
3755 static void delete_completion(GObject *obj, GtkWidget *entry) {
3756     GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3757     if (completion) {
3758         gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3759         g_object_unref (completion);
3760     }
3763 GtkWidget*
3764 sp_text_toolbox_new (SPDesktop *desktop)
3766     GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
3768     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3769     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3771     GtkTooltips *tt = gtk_tooltips_new();
3772     Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3774     ////////////Family
3775     //Window
3776     GtkWidget   *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3777     gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3779     //Entry
3780     GtkWidget           *entry = gtk_entry_new ();
3781     gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3782     GtkEntryCompletion  *completion = gtk_entry_completion_new ();
3783     gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3784     gtk_entry_completion_set_text_column (completion, 0);
3785     gtk_entry_completion_set_minimum_key_length (completion, 1);
3786     g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3787     gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3788     gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
3789     aux_toolbox_space (tbl, 1);
3790     gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3791     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
3793     //Button
3794     GtkWidget   *button = gtk_button_new ();
3795     gtk_container_add       (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3796     gtk_box_pack_start      (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3798     //Popdown
3799     GtkWidget           *sw = gtk_scrolled_window_new (NULL, NULL);
3800     GtkWidget           *treeview = gtk_tree_view_new ();
3802     GtkCellRenderer     *cell = gtk_cell_renderer_text_new ();
3803     GtkTreeViewColumn   *column = gtk_tree_view_column_new ();
3804     gtk_tree_view_column_pack_start (column, cell, FALSE);
3805     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3806     gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3807     gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3809     gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3810     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3811 #if GTK_CHECK_VERSION(2,6,0)
3812     gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3813 #endif // GTK_CHECK_VERSION(2,6,0)
3815     //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3817     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
3818     gtk_container_add (GTK_CONTAINER (sw), treeview);
3820     gtk_container_add (GTK_CONTAINER (window), sw);
3821     gtk_widget_set_size_request (window, 300, 450);
3823     g_signal_connect (G_OBJECT (entry),  "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3824     g_signal_connect (G_OBJECT (entry),  "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3825     g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3827     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3829     g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3830     g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3832     GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3833     g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3835     g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3836     g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3837     g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3838     g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3839     g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3841     GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3842     aux_toolbox_space (tbl, 1);
3843     GtkWidget *box = gtk_event_box_new ();
3844     gtk_container_add (GTK_CONTAINER (box), image);
3845     gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3846     g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3847     GtkTooltips *tooltips = gtk_tooltips_new ();
3848     gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3849     gtk_widget_hide (GTK_WIDGET (box));
3850     g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3852     ////////////Size
3853     const char *sizes[] = {
3854         "4", "6", "8", "9", "10", "11", "12", "13", "14",
3855         "16", "18", "20", "22", "24", "28",
3856         "32", "36", "40", "48", "56", "64", "72", "144"
3857     };
3859     GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3860     for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3861     gtk_widget_set_size_request (cbox, 80, -1);
3862     aux_toolbox_space (tbl, 1);
3863     gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3864     g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3865     g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3866     gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3868     //spacer
3869     aux_toolbox_space (tbl, 4);
3870     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3872     ////////////Text anchor
3873     GtkWidget *group   = gtk_radio_button_new (NULL);
3874     GtkWidget *row     = gtk_hbox_new (FALSE, 4);
3875     g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3877     // left
3878     GtkWidget *rbutton = group;
3879     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3880     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3881     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3883     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3884     g_object_set_data   (G_OBJECT (tbl), "text-start", rbutton);
3885     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3886     gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3888     // center
3889     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3890     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3891     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3892     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3894     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3895     g_object_set_data   (G_OBJECT (tbl), "text-middle", rbutton);
3896     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
3897     gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3899     // right
3900     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3901     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3902     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3903     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3905     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3906     g_object_set_data   (G_OBJECT (tbl), "text-end", rbutton);
3907     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3908     gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3910     // fill
3911     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3912     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3913     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3914     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3916     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3917     g_object_set_data   (G_OBJECT (tbl), "text-fill", rbutton);
3918     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3919     gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3921     aux_toolbox_space (tbl, 1);
3922     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3924     //spacer
3925     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3927     ////////////Text style
3928     row = gtk_hbox_new (FALSE, 4);
3930     // bold
3931     rbutton = gtk_toggle_button_new ();
3932     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3933     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3934     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3935     gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3937     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3938     g_object_set_data   (G_OBJECT (tbl), "style-bold", rbutton);
3939     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3941     // italic
3942     rbutton = gtk_toggle_button_new ();
3943     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3944     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3945     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3946     gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3948     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3949     g_object_set_data   (G_OBJECT (tbl), "style-italic", rbutton);
3950     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
3952     aux_toolbox_space (tbl, 1);
3953     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3955     //spacer
3956     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3958     ////////////Text orientation
3959     group   = gtk_radio_button_new (NULL);
3960     row     = gtk_hbox_new (FALSE, 4);
3961     g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3963     // horizontal
3964     rbutton = group;
3965     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3966     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
3967     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3968     gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3970     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3971     g_object_set_data   (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3972     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3974     // vertical
3975     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3976     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3977     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
3978     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3979     gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3981     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3982     g_object_set_data   (G_OBJECT (tbl), "orientation-vertical", rbutton);
3983     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
3984     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3987     //watch selection
3988     Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3990     sigc::connection *c_selection_changed =
3991         new sigc::connection (sp_desktop_selection (desktop)->connectChanged
3992                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3993     pool->add_connection ("selection-changed", c_selection_changed);
3995     sigc::connection *c_selection_modified =
3996         new sigc::connection (sp_desktop_selection (desktop)->connectModified
3997                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3998     pool->add_connection ("selection-modified", c_selection_modified);
4000     sigc::connection *c_subselection_changed =
4001         new sigc::connection (desktop->connectToolSubselectionChanged
4002                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4003     pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4005     Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4008 #if 0
4009     // horizontal
4010     {
4011         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
4012         GtkWidget *b = group = gtk_radio_button_new (NULL);
4013         gtk_container_add (GTK_CONTAINER (b), px);
4014         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
4015         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4016         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4017         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4018     }
4020     // vertical
4021     {
4022         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
4023         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4024         gtk_container_add (GTK_CONTAINER (b), px);
4025         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
4026         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4027         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4028         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4029     }
4031     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4033     // letter spacing
4034     {
4035         {
4036             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
4037             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4038             gtk_container_add (GTK_CONTAINER (hb), image);
4039             gtk_widget_show(image);
4040             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4041         }
4043         {
4044             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
4045                                              "tools.text", "letter_spacing", 0.0,
4046                                              us, tbl, FALSE, NULL,
4047                                              -1000.0, 1000.0, 0.1, 0.1,
4048                                              sp_text_letter_changed, 0.1, 1);
4049             gtk_widget_set_size_request (hb, 45, 6);
4050             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4051         }
4052     }
4054     // line spacing
4055     {
4056         {
4057             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
4058             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4059             gtk_container_add (GTK_CONTAINER (hb), image);
4060             gtk_widget_show(image);
4061             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4062         }
4064         {
4065             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
4066                                              "tools.text", "line_spacing", 0,
4067                                              us, tbl, FALSE, NULL,
4068                                              -1000.0, 1000.0, 0.1, 0.1,
4069                                              sp_text_line_changed, 0.1, 1);
4070             gtk_widget_set_size_request (hb, 45, 0);
4071             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
4072         }
4073     }
4075     {
4076         // horizontal kerning/vertical kerning units menu: create
4077         GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
4078         sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
4079         sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
4081         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4083         // horizontal kerning
4084         {
4085             {
4086                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
4087                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4088                 gtk_container_add (GTK_CONTAINER (hb), image);
4089                 gtk_widget_show(image);
4090                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4091             }
4093             {
4094                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
4095                                                  "tools.text", "horizontal_kerning", 0,
4096                                                  us, tbl, FALSE, NULL,
4097                                                  -100.00, 100.00, 0.01, 0.1,
4098                                                  sp_text_horiz_kern_changed);
4099                 gtk_widget_set_size_request (hb, 45, 0);
4100                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4101             }
4102         }
4104         // vertical kerning
4105         {
4106             {
4107                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
4108                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4109                 gtk_container_add (GTK_CONTAINER (hb), image);
4110                 gtk_widget_show(image);
4111                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4112             }
4114             {
4115                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
4116                                                  "tools.text", "vertical_kerning", 0,
4117                                                  us, tbl, FALSE, NULL,
4118                                                  -100.00, 100.00, 0.01, 0.1,
4119                                                  sp_text_vert_kern_changed);
4120                 gtk_widget_set_size_request (hb, 45, 0);
4121                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
4122             }
4123         }
4125         // add the units menu
4126         gtk_widget_show(us);
4127         gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
4128         gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
4129     }
4131     // letter rotation
4132     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4133     {
4134         {
4135             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
4136             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4137             gtk_container_add (GTK_CONTAINER (hb), image);
4138             gtk_widget_show(image);
4139             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4140         }
4141         {
4142             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
4143                                              "tools.text", "letter_rotation", 0,
4144                                              us, tbl, FALSE, NULL,
4145                                              -180.0, 180.0, 0.1, 0.1,
4146                                              sp_text_letter_rotation_changed, 0.1, 1);
4147             gtk_widget_set_size_request (hb, 45, 0);
4148             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4149         }
4150         // rotation degree label
4151         {
4152             GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4153             gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4154         }
4155     }
4157     // Remove Manual Kerns
4158     {
4159         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4160         GtkWidget *button = gtk_button_new ();
4161         gtk_container_add (GTK_CONTAINER (button), px);
4162         gtk_widget_show(button);
4163         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4164         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4165         gtk_widget_set_sensitive(button, TRUE);
4166         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4167     }
4168 #endif
4170     gtk_widget_show_all (tbl);
4171     return tbl;
4173 } // end of sp_text_toolbox_new()
4175 }//<unnamed> namespace
4178 //#########################
4179 //##  Connector Toolbox  ##
4180 //#########################
4182 static void sp_connector_path_set_avoid(void)
4184     cc_selection_set_avoid(true);
4188 static void sp_connector_path_set_ignore(void)
4190     cc_selection_set_avoid(false);
4195 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
4197     // quit if run by the _changed callbacks
4198     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4199         return;
4200     }
4202     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
4203             "desktop");
4204     SPDocument *doc = sp_desktop_document(desktop);
4206     if (!sp_document_get_undo_sensitive(doc))
4207     {
4208         return;
4209     }
4211     // in turn, prevent callbacks from responding
4212     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
4214     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4216     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4217     SP_OBJECT(desktop->namedview)->updateRepr();
4219     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4220     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4221         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4222         NR::Matrix m = NR::identity();
4223         avoid_item_move(&m, item);
4224     }
4226     if (items) {
4227         g_slist_free(items);
4228     }
4230     sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4231             _("Change connector spacing"));
4233     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
4235     spinbutton_defocus(GTK_OBJECT(tbl));
4238 static void sp_connector_graph_layout(void)
4240     if (!SP_ACTIVE_DESKTOP) return;
4242     // hack for clones, see comment in align-and-distribute.cpp
4243     int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4244     prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4246     graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4248     prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4250     sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4253 static void
4254 sp_directed_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4256     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4257         prefs_set_string_attribute("tools.connector", "directedlayout",
4258                 "true");
4259     } else {
4260         prefs_set_string_attribute("tools.connector", "directedlayout",
4261                 "false");
4262     }
4264 static void
4265 sp_nooverlaps_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4267     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4268         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4269                 "true");
4270     } else {
4271         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4272                 "false");
4273     }
4277 static void connector_length_changed(GtkAdjustment *adj, GtkWidget *tbl)
4279     prefs_set_double_attribute("tools.connector", "length", adj->value);
4280     spinbutton_defocus(GTK_OBJECT(tbl));
4283 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4284         gchar const *name, gchar const *old_value, gchar const *new_value,
4285         bool is_interactive, gpointer data)
4287     GtkWidget *tbl = GTK_WIDGET(data);
4289     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4290         return;
4291     }
4292     if (strcmp(name, "inkscape:connector-spacing") != 0) {
4293         return;
4294     }
4296     GtkAdjustment *adj = (GtkAdjustment*)
4297             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4298     gdouble spacing = defaultConnSpacing;
4299     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4301     gtk_adjustment_set_value(adj, spacing);
4305 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4306     NULL, /* child_added */
4307     NULL, /* child_removed */
4308     connector_tb_event_attr_changed,
4309     NULL, /* content_changed */
4310     NULL  /* order_changed */
4311 };
4314 static GtkWidget *
4315 sp_connector_toolbox_new(SPDesktop *desktop)
4317     GtkTooltips *tt = gtk_tooltips_new();
4318     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
4320     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4321     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4323     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4324             AUX_BETWEEN_BUTTON_GROUPS);
4326     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4327             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
4328             tt, _("Make connectors avoid selected objects"));
4330     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4331             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
4332             tt, _("Make connectors ignore selected objects"));
4334     //  interval
4335     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4336             AUX_BETWEEN_BUTTON_GROUPS);
4338     // Spacing spinbox
4339     {
4340         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
4341                 _("The amount of space left around objects by auto-routing connectors"),
4342                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
4343                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
4344                 connector_spacing_changed, 1, 0);
4346         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
4347                 AUX_SPACING);
4348     }
4349     // Graph (connector network) layout
4350     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4351             "graph_layout", GTK_SIGNAL_FUNC(sp_connector_graph_layout),
4352             tt, _("Nicely arrange selected connector network"));
4353     // Default connector length spinbox
4354     {
4355         GtkWidget *connector_length = sp_tb_spinbutton(_("Length:"),
4356                 _("Ideal length for connectors when layout is applied"),
4357                 "tools.connector", "length", 100, NULL, tbl, TRUE,
4358                 "inkscape:connector-length", 10, 1000, 10.0, 100.0,
4359                 connector_length_changed, 1, 0);
4361         gtk_box_pack_start(GTK_BOX(tbl), connector_length, FALSE, FALSE,
4362                 AUX_SPACING);
4363     }
4364     gchar const *tbuttonstate;
4365     // Directed edges toggle button
4366     {
4367         GtkWidget *tbutton = gtk_toggle_button_new ();
4368         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4369         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "directed_graph"));
4370         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4371         gtk_tooltips_set_tip(tt, tbutton, _("Make connectors with end-markers (arrows) point downwards"), NULL);
4373         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4374         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_directed_graph_layout_toggled), tbl);
4375         tbuttonstate = prefs_get_string_attribute("tools.connector", "directedlayout");
4376         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4377                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4378     }
4379     // Avoid overlaps toggle button
4380     {
4381         GtkWidget *tbutton = gtk_toggle_button_new ();
4382         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4383         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "remove_overlaps"));
4384         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4385         gtk_tooltips_set_tip(tt, tbutton, _("Do not allow overlapping shapes"), NULL);
4387         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4388         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_nooverlaps_graph_layout_toggled), tbl);
4389         tbuttonstate = prefs_get_string_attribute("tools.connector", "avoidoverlaplayout");
4390         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4391                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4392     }
4394     gtk_widget_show_all(tbl);
4395     sp_set_font_size_smaller (tbl);
4397     // Code to watch for changes to the connector-spacing attribute in
4398     // the XML.
4399     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4400     g_assert(repr != NULL);
4402     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
4403             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
4405     if (oldrepr) { // remove old listener
4406         sp_repr_remove_listener_by_data(oldrepr, tbl);
4407         Inkscape::GC::release(oldrepr);
4408         oldrepr = NULL;
4409         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
4410     }
4412     if (repr) {
4413         g_object_set_data(G_OBJECT(tbl), "repr", repr);
4414         Inkscape::GC::anchor(repr);
4415         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
4416         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
4417     }
4419     return tbl;
4421 } // end of sp_connector_toolbox_new()
4423 static void paintbucket_channels_changed(EgeSelectOneAction* act, GtkWidget* tbl)
4425     gint channels = ege_select_one_action_get_active( act );
4426     flood_channels_set_channels( channels );
4429 static void paintbucket_threshold_changed(GtkAdjustment *adj, GtkWidget *tbl)
4431     prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4434 static void paintbucket_offset_changed(GtkAdjustment *adj, GtkWidget *tbl)
4436     UnitTracker* tracker = reinterpret_cast<UnitTracker*>(gtk_object_get_data(GTK_OBJECT(tbl), "tracker"));
4437     SPUnit const *unit = tracker->getActiveUnit();
4440     prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
4441     spinbutton_defocus(GTK_OBJECT(tbl));
4444 static GtkWidget *
4445 sp_paintbucket_toolbox_new(SPDesktop *desktop)
4447     GtkWidget *holder = gtk_hbox_new(FALSE, 0);
4448     gtk_object_set_data(GTK_OBJECT(holder), "dtw", desktop->canvas);
4449     gtk_object_set_data(GTK_OBJECT(holder), "desktop", desktop);
4451     gchar const * descr =
4452         "<ui>"
4453         "  <toolbar name='PaintbucketToolbar'>"
4454         "    <toolitem action='ChannelsAction' />"
4455         "    <separator />"
4456         "    <toolitem action='ThresholdAction' />"
4457         "    <separator />"
4458         "    <toolitem action='OffsetAction' />"
4459         "  </toolbar>"
4460         "</ui>";
4461     GtkActionGroup* mainActions = gtk_action_group_new("main");
4463     EgeAdjustmentAction* eact = 0;
4465     {
4466         GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4468         GList* items = 0;
4469         gint count = 0;
4470         for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
4471         {
4472             GtkTreeIter iter;
4473             gtk_list_store_append( model, &iter );
4474             gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4475             count++;
4476         }
4477         g_list_free( items );
4478         items = 0;
4479         EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by:"), _(""), NULL, GTK_TREE_MODEL(model) );
4480         ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
4481         g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
4482         gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
4483     }
4485     // Spacing spinbox
4486     {
4487         eact = create_adjustment_action(
4488             "ThresholdAction",
4489             _("Threshold:"),
4490             _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
4491             "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
4492             "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
4493             0, 0, 0,
4494             paintbucket_threshold_changed, 1, 0 );
4496         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4497     }
4499     // Create the units menu.
4500     UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
4501     tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
4502     gtk_object_set_data( GTK_OBJECT(holder), "tracker", tracker );
4503     {
4504         GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), _("") );
4505         gtk_action_group_add_action( mainActions, act );
4506     }
4508     // Offset spinbox
4509     {
4510         eact = create_adjustment_action(
4511             "OffsetAction",
4512             _("Grow/shrink by:"),
4513             _("The amount to grow (positive) or shrink (negative) the created fill path"),
4514             "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
4515             "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
4516             0, 0, 0,
4517             paintbucket_offset_changed, 1, 2);
4518         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
4520         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4521     }
4524     GtkUIManager* mgr = gtk_ui_manager_new();
4525     GError* errVal = 0;
4527     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
4528     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
4530     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/PaintbucketToolbar" );
4531     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
4532     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
4534     gtk_box_pack_start( GTK_BOX(holder), toolBar, TRUE, TRUE, 0 );
4537     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of Paint Bucket fill objects"));
4538     swatch->setDesktop (desktop);
4539     swatch->setClickVerb (SP_VERB_CONTEXT_PAINTBUCKET_PREFS);
4540     swatch->setWatchedTool ("tools.paintbucket", true);
4541     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
4542     gtk_box_pack_end( GTK_BOX(holder), swatch_, FALSE, FALSE, 0 );
4544     gtk_widget_show_all( holder );
4545     sp_set_font_size_smaller( holder );
4547     return holder;
4550 /*
4551   Local Variables:
4552   mode:c++
4553   c-file-style:"stroustrup"
4554   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4555   indent-tabs-mode:nil
4556   fill-column:99
4557   End:
4558 */
4559 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :