Code

Switched paint bucket toolbar to stock GTK+ toobar, including minor MVC cleanup on...
[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_DRAWING,
307         SP_VERB_ZOOM_PAGE,
308         SP_VERB_ZOOM_SELECTION
309     };
311     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
312     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
314     static std::map<SPDesktop*, GtkActionGroup*> groups;
315     GtkActionGroup* mainActions = 0;
316     if ( groups.find(desktop) != groups.end() ) {
317         mainActions = groups[desktop];
318     }
320     if ( !mainActions ) {
321         mainActions = gtk_action_group_new("main");
322         groups[desktop] = mainActions;
323     }
325     for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
326         Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
327         if ( verb ) {
328             if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
329                 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
330                 gtk_action_group_add_action( mainActions, act );
331             }
332         }
333     }
335     return mainActions;
339 GtkWidget *
340 sp_tool_toolbox_new()
342     GtkTooltips *tt = gtk_tooltips_new();
343     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
345     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
346     g_object_set_data(G_OBJECT(tb), "tooltips", tt);
348     gtk_widget_set_sensitive(tb, FALSE);
350     GtkWidget *hb = gtk_handle_box_new();
351     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
352     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
353     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
355     gtk_container_add(GTK_CONTAINER(hb), tb);
356     gtk_widget_show(GTK_WIDGET(tb));
358     sigc::connection* conn = new sigc::connection;
359     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
361     return hb;
364 static void
365 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
367     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
368     gtk_widget_queue_resize(child);
371 static void
372 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
374     g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
375     gtk_widget_queue_resize(child);
378 GtkWidget *
379 sp_aux_toolbox_new()
381     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
383     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
384     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
385     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
386     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
387     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
389     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
390     g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
392     gtk_widget_set_sensitive(tb, FALSE);
394     GtkWidget *hb = gtk_handle_box_new();
395     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
396     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
397     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
399     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
400     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
402     gtk_container_add(GTK_CONTAINER(hb), tb);
403     gtk_widget_show(GTK_WIDGET(tb));
405     sigc::connection* conn = new sigc::connection;
406     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
408     return hb;
411 //####################################
412 //# Commands Bar
413 //####################################
415 GtkWidget *
416 sp_commands_toolbox_new()
418     GtkWidget *tb = gtk_vbox_new(FALSE, 0);
420     GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
421     GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
422     gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
423     gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
424     gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
426     g_object_set_data(G_OBJECT(tb), "desktop", NULL);
427     gtk_widget_set_sensitive(tb, FALSE);
429     GtkWidget *hb = gtk_handle_box_new();
430     gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
431     gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
432     gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
434     g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
435     g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
437     gtk_container_add(GTK_CONTAINER(hb), tb);
438     gtk_widget_show(GTK_WIDGET(tb));
440     sigc::connection* conn = new sigc::connection;
441     g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
443     return hb;
447 //####################################
448 //# node editing callbacks
449 //####################################
451 void
452 sp_node_path_edit_add(void)
454     sp_node_selected_add_node();
457 void
458 sp_node_path_edit_delete(void)
460     sp_node_selected_delete();
463 void
464 sp_node_path_edit_delete_segment(void)
466     sp_node_selected_delete_segment();
469 void
470 sp_node_path_edit_break(void)
472     sp_node_selected_break();
475 void
476 sp_node_path_edit_join(void)
478     sp_node_selected_join();
481 void
482 sp_node_path_edit_join_segment(void)
484     sp_node_selected_join_segment();
487 void
488 sp_node_path_edit_toline(void)
490     sp_node_selected_set_line_type(NR_LINETO);
493 void
494 sp_node_path_edit_tocurve(void)
496     sp_node_selected_set_line_type(NR_CURVETO);
499 void
500 sp_node_path_edit_cusp(void)
502     sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
505 void
506 sp_node_path_edit_smooth(void)
508     sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
511 void
512 sp_node_path_edit_symmetrical(void)
514     sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
517 static void toggle_show_handles (GtkWidget *button, gpointer data) {
518     bool show = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
519     prefs_set_int_attribute ("tools.nodes", "show_handles",  show ? 1 : 0);
520     sp_nodepath_show_handles(show);
523 //################################
524 //##    Node Editing Toolbox    ##
525 //################################
527 static GtkWidget *
528 sp_node_toolbox_new(SPDesktop *desktop)
530     Inkscape::UI::View::View *view = desktop;
532     GtkTooltips *tt = gtk_tooltips_new();
533     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
535     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
537     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_insert",
538         GTK_SIGNAL_FUNC(sp_node_path_edit_add), tt, _("Insert new nodes into selected segments"));
539     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete",
540         GTK_SIGNAL_FUNC(sp_node_path_edit_delete), tt, _("Delete selected nodes"));
542     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
544     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join",
545         GTK_SIGNAL_FUNC(sp_node_path_edit_join), tt, _("Join selected endnodes"));
546     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_join_segment",
547         GTK_SIGNAL_FUNC(sp_node_path_edit_join_segment), tt, _("Join selected endnodes with a new segment"));
549     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_delete_segment",
550         GTK_SIGNAL_FUNC(sp_node_path_edit_delete_segment), tt, _("Split path between two non-endpoint nodes"));
552     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_break",
553         GTK_SIGNAL_FUNC(sp_node_path_edit_break), tt, _("Break path at selected nodes"));
555     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
557     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_cusp",
558         GTK_SIGNAL_FUNC(sp_node_path_edit_cusp), tt, _("Make selected nodes corner"));
560     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_smooth",
561         GTK_SIGNAL_FUNC(sp_node_path_edit_smooth), tt, _("Make selected nodes smooth"));
563     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_symmetric",
564         GTK_SIGNAL_FUNC(sp_node_path_edit_symmetrical), tt, _("Make selected nodes symmetric"));
566     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
568     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_line",
569         GTK_SIGNAL_FUNC(sp_node_path_edit_toline), tt, _("Make selected segments lines"));
571     sp_toolbox_button_new(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, "node_curve",
572         GTK_SIGNAL_FUNC(sp_node_path_edit_tocurve), tt, _("Make selected segments curves"));
574     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
576     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_OBJECT_TO_CURVE), view, tt);
578     sp_toolbox_button_normal_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, Inkscape::Verb::get(SP_VERB_SELECTION_OUTLINE), view, tt);
580     aux_toolbox_space(tb, AUX_BETWEEN_BUTTON_GROUPS);
582     GtkWidget *cvbox = gtk_vbox_new (FALSE, 0);
583     GtkWidget *cbox = gtk_hbox_new (FALSE, 0);
585     {
586     GtkWidget *button = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
587                                               SP_BUTTON_TYPE_TOGGLE,
588                                               NULL,
589                                               "nodes_show_handles",
590                                               _("Show the Bezier handles of selected nodes"),
591                                               tt);
592     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), prefs_get_int_attribute ("tools.nodes", "show_handles", 1));
593     g_signal_connect_after (G_OBJECT (button), "clicked", G_CALLBACK (toggle_show_handles), desktop);
594     gtk_box_pack_start(GTK_BOX(cbox), button, FALSE, FALSE, 0);
595     }
597     gtk_box_pack_start(GTK_BOX(cvbox), cbox, TRUE, FALSE, 0);
598     gtk_box_pack_start(GTK_BOX(tb), cvbox, FALSE, FALSE, 0);
600     gtk_widget_show_all(tb);
602     return tb;
604 } // end of sp_node_toolbox_new()
607 //########################
608 //##    Zoom Toolbox    ##
609 //########################
611 static GtkWidget *
612 sp_zoom_toolbox_new(SPDesktop *desktop)
614     Inkscape::UI::View::View *view=desktop;
616     GtkTooltips *tt = gtk_tooltips_new();
617     GtkWidget *tb = gtk_hbox_new(FALSE, 0);
619     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0),
620                        FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
622     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_IN), view, tt);
624     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_OUT), view, tt);
626     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
628     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_SELECTION), view, tt);
630     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_DRAWING), view, tt);
632     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE), view, tt);
634     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PAGE_WIDTH), view, tt);
636     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
638     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_PREV), view, tt);
640     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_NEXT), view, tt);
642     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
644     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_1), view, tt);
646     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_1_2), view, tt);
648     sp_toolbox_button_new_from_verb(tb, Inkscape::ICON_SIZE_SMALL_TOOLBAR, SP_BUTTON_TYPE_NORMAL, Inkscape::Verb::get(SP_VERB_ZOOM_2_1), view, tt);
650     gtk_widget_show_all(tb);
652     return tb;
654 } // end of sp_zoom_toolbox_new()
656 void
657 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
659     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")));
663 void
664 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
666     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")));
669 void
670 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
672     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")));
675 static void
676 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
678     gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
679     SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
681     if (old_desktop) {
682         GList *children, *iter;
684         children = gtk_container_get_children(GTK_CONTAINER(toolbox));
685         for ( iter = children ; iter ; iter = iter->next ) {
686             gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
687         }
688         g_list_free(children);
689     }
691     g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
693     if (desktop) {
694         gtk_widget_set_sensitive(toolbox, TRUE);
695         setup_func(toolbox, desktop);
696         update_func(desktop, desktop->event_context, toolbox);
697         *conn = desktop->connectEventContextChanged
698             (sigc::bind (sigc::ptr_fun(update_func), toolbox));
699     } else {
700         gtk_widget_set_sensitive(toolbox, FALSE);
701     }
703 } // end of toolbox_set_desktop()
706 static void
707 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
709     GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
710     gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
711     Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
713     for (int i = 0 ; tools[i].type_name ; i++ ) {
714         GtkWidget *button =
715             sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
716                                                               SP_BUTTON_TYPE_TOGGLE,
717                                                               Inkscape::Verb::get(tools[i].verb),
718                                                               Inkscape::Verb::get(tools[i].doubleclick_verb),
719                                                               desktop,
720                                                               tooltips );
722         g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
723                            (gpointer)button );
724     }
728 static void
729 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
731     gchar const *const tname = ( eventcontext
732                                  ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
733                                  : NULL );
734     for (int i = 0 ; tools[i].type_name ; i++ ) {
735         SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
736         sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
737     }
740 static void
741 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
743     GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
745     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
746         GtkWidget *sub_toolbox;
747         if (aux_toolboxes[i].create_func == NULL)
748             sub_toolbox = sp_empty_toolbox_new(desktop);
749         else
750             sub_toolbox = aux_toolboxes[i].create_func(desktop);
752         gtk_size_group_add_widget( grouper, sub_toolbox );
754         gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
755         g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
756     }
757     g_object_unref( G_OBJECT(grouper) );
760 static void
761 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
763     gchar const *tname = ( eventcontext
764                            ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
765                            : NULL );
766     for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
767         GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
768         if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
769             gtk_widget_show_all(sub_toolbox);
770             g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
771         } else {
772             gtk_widget_hide(sub_toolbox);
773         }
774     }
777 static void
778 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
780     gchar const * descr =
781         "<ui>"
782         "  <toolbar name='CommandsToolbar'>"
783         "    <toolitem action='FileNew' />"
784         "    <toolitem action='FileOpen' />"
785         "    <toolitem action='FileSave' />"
786         "    <toolitem action='FilePrint' />"
787         "    <separator />"
788         "    <toolitem action='FileImport' />"
789         "    <toolitem action='FileExport' />"
790         "    <separator />"
791         "    <toolitem action='EditUndo' />"
792         "    <toolitem action='EditRedo' />"
793         "    <separator />"
794         "    <toolitem action='EditCopy' />"
795         "    <toolitem action='EditCut' />"
796         "    <toolitem action='EditPaste' />"
797         "    <separator />"
798         "    <toolitem action='ZoomSelection' />"
799         "    <toolitem action='ZoomDrawing' />"
800         "    <toolitem action='ZoomPage' />"
801         "    <separator />"
802         "    <toolitem action='EditDuplicate' />"
803         "    <toolitem action='EditClone' />"
804         "    <toolitem action='EditUnlinkClone' />"
805         "    <separator />"
806         "    <toolitem action='SelectionGroup' />"
807         "    <toolitem action='SelectionUnGroup' />"
808         "    <separator />"
809         "    <toolitem action='DialogFillStroke' />"
810         "    <toolitem action='DialogText' />"
811         "    <toolitem action='DialogXMLEditor' />"
812         "    <toolitem action='DialogAlignDistribute' />"
813         "    <separator />"
814         "    <toolitem action='DialogPreferences' />"
815         "    <toolitem action='DialogDocumentProperties' />"
816         "  </toolbar>"
817         "</ui>";
818     GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
821     GtkUIManager* mgr = gtk_ui_manager_new();
822     GError* errVal = 0;
824     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
825     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
827     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
828     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
829     gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
830     Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
831     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
834     gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
837 static void
838 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
842 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
844     gtk_widget_show(toolbox_toplevel);
845     GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
847     GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
848     if (!shown_toolbox) {
849         return;
850     }
851     gtk_widget_show(toolbox);
853     // need to show the spacer, or the padding will be off
854     GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
855     gtk_widget_show(spacer);
857     gtk_widget_show_all(shown_toolbox);
860 void
861 aux_toolbox_space(GtkWidget *tb, gint space)
863     gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
866 static GtkWidget *
867 sp_empty_toolbox_new(SPDesktop *desktop)
869     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
870     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
871     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
873     gtk_widget_show_all(tbl);
874     sp_set_font_size_smaller (tbl);
876     return tbl;
879 // helper UI functions
881 GtkWidget *
882 sp_tb_spinbutton(
883     gchar *label, gchar const *tooltip,
884     gchar const *path, gchar const *data, gdouble def,
885     GtkWidget *us,
886     GtkWidget *tbl,
887     gboolean altx, gchar const *altx_mark,
888     gdouble lower, gdouble upper, gdouble step, gdouble page,
889     void (*callback)(GtkAdjustment *, GtkWidget *),
890     gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
892     GtkTooltips *tt = gtk_tooltips_new();
894     GtkWidget *hb = gtk_hbox_new(FALSE, 1);
896     GtkWidget *l = gtk_label_new(label);
897     gtk_widget_show(l);
898     gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
899     gtk_container_add(GTK_CONTAINER(hb), l);
901     GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
902                                       lower, upper, step, page, page);
903     gtk_object_set_data(GTK_OBJECT(tbl), data, a);
904     if (us)
905         sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
907     GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
908     gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
909     if (altx)
910         gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
911     gtk_widget_set_size_request(sb,
912                                 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
913                                 AUX_SPINBUTTON_HEIGHT);
914     gtk_widget_show(sb);
915     gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
916     gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
917     gtk_container_add(GTK_CONTAINER(hb), sb);
918     gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
920     return hb;
923 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
924                                                        gchar const *label, gchar const *tooltip,
925                                                        gchar const *path, gchar const *data, gdouble def,
926                                                        GtkWidget *focusTarget,
927                                                        GtkWidget *us,
928                                                        GtkWidget *dataKludge,
929                                                        gboolean altx, gchar const *altx_mark,
930                                                        gdouble lower, gdouble upper, gdouble step, gdouble page,
931                                                        gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
932                                                        void (*callback)(GtkAdjustment *, GtkWidget *),
933                                                        gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
935     GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
936                                                              lower, upper, step, page, page ) );
937     if (us) {
938         sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
939     }
941     gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
943     EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
945     if ( (descrCount > 0) && descrLabels && descrValues ) {
946         ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
947     }
949     if ( focusTarget ) {
950         ege_adjustment_action_set_focuswidget( act, focusTarget );
951     }
953     if ( altx && altx_mark ) {
954         g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
955     }
957     if ( dataKludge ) {
958         gtk_object_set_data( GTK_OBJECT(dataKludge), data, adj );
959     }
961     // Using a cast just to make sure we pass in the right kind of function pointer
962     g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
964     return act;
968 #define MODE_LABEL_WIDTH 70
970 //########################
971 //##       Star         ##
972 //########################
974 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
976     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
978     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
979         // do not remember prefs if this call is initiated by an undo change, because undoing object
980         // creation sets bogus values to its attributes before it is deleted
981         prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
982     }
984     // quit if run by the attr_changed listener
985     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
986         return;
987     }
989     // in turn, prevent listener from responding
990     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
992     bool modmade = false;
994     Inkscape::Selection *selection = sp_desktop_selection(desktop);
995     GSList const *items = selection->itemList();
996     for (; items != NULL; items = items->next) {
997         if (SP_IS_STAR((SPItem *) items->data)) {
998             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
999             sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1000             sp_repr_set_svg_double(repr, "sodipodi:arg2",
1001                                    (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1002                                     + M_PI / (gint)adj->value));
1003             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1004             modmade = true;
1005         }
1006     }
1007     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1008                                    _("Star: Change number of corners"));
1010     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1013 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
1015     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1017     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1018         prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1019     }
1021     // quit if run by the attr_changed listener
1022     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1023         return;
1024     }
1026     // in turn, prevent listener from responding
1027     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1029     bool modmade = false;
1030     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1031     GSList const *items = selection->itemList();
1032     for (; items != NULL; items = items->next) {
1033         if (SP_IS_STAR((SPItem *) items->data)) {
1034             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1036             gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1037             gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1038             if (r2 < r1) {
1039                 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1040             } else {
1041                 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1042             }
1044             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1045             modmade = true;
1046         }
1047     }
1049     if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1050                                    _("Star: Change spoke ratio"));
1052     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1055 static void sp_stb_sides_flat_state_changed( GtkToggleAction *act, GtkObject *dataKludge )
1057     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1058     bool flat = gtk_toggle_action_get_active(act);
1060     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1061         prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1062                                     flat ? "true" : "false" );
1063     }
1065     // quit if run by the attr_changed listener
1066     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1067         return;
1068     }
1070     // in turn, prevent listener from responding
1071     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1073     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1074     GSList const *items = selection->itemList();
1075     GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(dataKludge), "prop_action") );
1076     bool modmade = false;
1078     if ( prop_action ) {
1079         gtk_action_set_sensitive( prop_action, !flat );
1080     }
1082     for (; items != NULL; items = items->next) {
1083         if (SP_IS_STAR((SPItem *) items->data)) {
1084             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1085             repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1086             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1087             modmade = true;
1088         }
1089     }
1091     if (modmade) {
1092         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1093                          flat ? _("Make polygon") : _("Make star"));
1094     }
1096     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1099 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
1101     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1103     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1104         prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1105     }
1107     // quit if run by the attr_changed listener
1108     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1109         return;
1110     }
1112     // in turn, prevent listener from responding
1113     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1115     bool modmade = false;
1117     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1118     GSList const *items = selection->itemList();
1119     for (; items != NULL; items = items->next) {
1120         if (SP_IS_STAR((SPItem *) items->data)) {
1121             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1122             sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1123             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1124             modmade = true;
1125         }
1126     }
1127     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1128                                    _("Star: Change rounding"));
1130     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1133 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GtkWidget *dataKludge )
1135     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(dataKludge), "desktop");
1137     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1138         prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1139     }
1141     // quit if run by the attr_changed listener
1142     if (g_object_get_data(G_OBJECT(dataKludge), "freeze")) {
1143         return;
1144     }
1146     // in turn, prevent listener from responding
1147     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(TRUE));
1149     bool modmade = false;
1151     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1152     GSList const *items = selection->itemList();
1153     for (; items != NULL; items = items->next) {
1154         if (SP_IS_STAR((SPItem *) items->data)) {
1155             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1156             sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1157             SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1158             modmade = true;
1159         }
1160     }
1161     if (modmade)  sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1162                                    _("Star: Change randomization"));
1164     g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
1168 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1169                                        gchar const *old_value, gchar const *new_value,
1170                                        bool is_interactive, gpointer data)
1172     GtkWidget *tbl = GTK_WIDGET(data);
1174     // quit if run by the _changed callbacks
1175     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1176         return;
1177     }
1179     // in turn, prevent callbacks from responding
1180     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1182     GtkAdjustment *adj = 0;
1184     if (!strcmp(name, "inkscape:randomized")) {
1185         adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1186         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1187     } else if (!strcmp(name, "inkscape:rounded")) {
1188         adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1189         gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1190     } else if (!strcmp(name, "inkscape:flatsided")) {
1191         GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1192         char const *flatsides = repr->attribute("inkscape:flatsided");
1193         if (flatsides && !strcmp(flatsides,"false" )) {
1194             GtkToggleAction* flat2_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat2_action" ) );
1195             gtk_toggle_action_set_active( flat2_action, TRUE );
1196             gtk_action_set_sensitive( prop_action, TRUE );
1197         } else {
1198             GtkToggleAction* flat_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1199             gtk_toggle_action_set_active( flat_action, TRUE );
1200             gtk_action_set_sensitive( prop_action, FALSE );
1201         }
1202     } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1203         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1204         gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1205         gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1206         if (r2 < r1) {
1207             gtk_adjustment_set_value(adj, r2/r1);
1208         } else {
1209             gtk_adjustment_set_value(adj, r1/r2);
1210         }
1211     } else if (!strcmp(name, "sodipodi:sides")) {
1212         adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1213         gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1214     }
1216     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1220 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1222     NULL, /* child_added */
1223     NULL, /* child_removed */
1224     star_tb_event_attr_changed,
1225     NULL, /* content_changed */
1226     NULL  /* order_changed */
1227 };
1230 /**
1231  *  \param selection Should not be NULL.
1232  */
1233 static void
1234 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1236     int n_selected = 0;
1237     Inkscape::XML::Node *repr = NULL;
1238     Inkscape::XML::Node *oldrepr = NULL;
1240     for (GSList const *items = selection->itemList();
1241          items != NULL;
1242          items = items->next)
1243     {
1244         if (SP_IS_STAR((SPItem *) items->data)) {
1245             n_selected++;
1246             repr = SP_OBJECT_REPR((SPItem *) items->data);
1247         }
1248     }
1250     EgeOutputAction* act = EGE_OUTPUT_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "mode_action") );
1252     if (n_selected == 0) {
1253         g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1254     } else if (n_selected == 1) {
1255         g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1257         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1258         if (oldrepr) { // remove old listener
1259             sp_repr_remove_listener_by_data(oldrepr, tbl);
1260             Inkscape::GC::release(oldrepr);
1261             oldrepr = 0;
1262             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1263         }
1265         if (repr) {
1266             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1267             Inkscape::GC::anchor(repr);
1268             sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1269             sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1270         }
1271     } else {
1272         // FIXME: implement averaging of all parameters for multiple selected stars
1273         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1274         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1275     }
1279 static void sp_stb_defaults( GtkWidget *widget, GtkWidget *dataKludge )
1281     // FIXME: in this and all other _default functions, set some flag telling the value_changed
1282     // callbacks to lump all the changes for all selected objects in one undo step
1284     GtkAdjustment *adj = 0;
1286     // fixme: make settable in prefs!
1287     gint mag = 5;
1288     gdouble prop = 0.5;
1289     gboolean flat = FALSE;
1290     gdouble randomized = 0;
1291     gdouble rounded = 0;
1293     GtkToggleAction* flat_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(dataKludge), "flat_action" ) );
1294     GtkToggleAction* flat2_action = GTK_TOGGLE_ACTION( g_object_get_data( G_OBJECT(dataKludge), "flat2_action" ) );
1295     gtk_toggle_action_set_active( flat ? flat_action : flat2_action, TRUE );
1297     GtkAction* sb2 = GTK_ACTION( g_object_get_data(G_OBJECT(dataKludge), "prop_action") );
1298     gtk_action_set_sensitive( sb2, !flat );
1300     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "magnitude") );
1301     gtk_adjustment_set_value(adj, mag);
1302     gtk_adjustment_value_changed(adj);
1304     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "proportion") );
1305     gtk_adjustment_set_value(adj, prop);
1306     gtk_adjustment_value_changed(adj);
1308     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "rounded") );
1309     gtk_adjustment_set_value(adj, rounded);
1310     gtk_adjustment_value_changed(adj);
1312     adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(dataKludge), "randomized") );
1313     gtk_adjustment_set_value(adj, randomized);
1314     gtk_adjustment_value_changed(adj);
1318 void
1319 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1321     GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1322     if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1323     GtkWidget *l = gtk_label_new(NULL);
1324     gtk_label_set_markup(GTK_LABEL(l), title);
1325     gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1326     gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1327     gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1331 static GtkWidget *
1332 sp_star_toolbox_new(SPDesktop *desktop)
1334     GtkWidget* holder = gtk_table_new( 1, 2, FALSE );
1336     gchar const * descr =
1337         "<ui>"
1338         "  <toolbar name='StarToolbar'>"
1339         "    <separator />"
1340         "    <toolitem action='StarStateAction' />"
1341         "    <separator />"
1342         "    <toolitem action='FlatAction' />"
1343         "    <toolitem action='FlatAction2' />"
1344         "    <separator />"
1345         "    <toolitem action='MagnitudeAction' />"
1346         "    <toolitem action='SpokeAction' />"
1347         "    <toolitem action='RoundednessAction' />"
1348         "    <toolitem action='RandomizationAction' />"
1349         "    <separator />"
1350         "    <toolitem action='ResetAction' />"
1351         "  </toolbar>"
1352         "</ui>";
1353     GtkActionGroup* mainActions = gtk_action_group_new("main");
1355     {
1356         EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1357         ege_output_action_set_use_markup( act, TRUE );
1358         gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1359         gtk_object_set_data( GTK_OBJECT(holder), "mode_action", act );
1360     }
1362     {
1363         gtk_object_set_data(GTK_OBJECT(holder), "dtw", desktop->canvas);
1364         gtk_object_set_data(GTK_OBJECT(holder), "desktop", desktop);
1366         //EgeAdjustmentAction* calligraphy_angle = 0;
1367         EgeAdjustmentAction* eact = 0;
1368         gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1369         bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1371         /* Flatsided checkbox */
1372         {
1373             InkRadioAction* act = ink_radio_action_new( "FlatAction",
1374                                                         _("Polygon"),
1375                                                         _("Regular polygon (with one handle) instead of a star"),
1376                                                         "star_flat",
1377                                                         Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1378             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1380             InkRadioAction* act2 = ink_radio_action_new( "FlatAction2",
1381                                                          _("Star"),
1382                                                          _("Star instead of a regular polygon (with one handle)"),
1383                                                          "star_angled",
1384                                                          Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1385             gtk_action_group_add_action( mainActions, GTK_ACTION( act2 ) );
1387             // Connect to be in the same radio button group.
1388             gtk_radio_action_set_group( GTK_RADIO_ACTION(act), 0 );
1389             GSList* radioGroup = gtk_radio_action_get_group( GTK_RADIO_ACTION(act) );
1390             gtk_radio_action_set_group( GTK_RADIO_ACTION(act2), radioGroup );
1392             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), isFlatSided );
1393             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act2), !isFlatSided );
1395             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1396             gtk_object_set_data( GTK_OBJECT(holder), "flat_action", act );
1397             gtk_object_set_data( GTK_OBJECT(holder), "flat2_action", act2 );
1398         }
1400         /* Magnitude */
1401         //gchar const* labels[] = {_("tri (default)"), _("quad"), _("pent")};
1402         //gdouble values[] = {3, 4, 5};
1403         eact = create_adjustment_action( "MagnitudeAction",
1404                                          _("Corners:"), _("Number of corners of a polygon or star"),
1405                                          "tools.shapes.star", "magnitude", 3,
1406                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1407                                          3, 1024, 1, 5,
1408                                          0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
1409                                          sp_stb_magnitude_value_changed,
1410                                          1.0, 0 );
1411         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1412         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1414         /* Spoke ratio */
1415         //gchar const* labels2[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1416         //gdouble values2[] = {-90, 0, 30, 90};
1417         eact = create_adjustment_action( "SpokeAction",
1418                                          _("Spoke ratio:"),
1419                                          // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1420                                          // Base radius is the same for the closest handle.
1421                                          _("Base radius to tip radius ratio"),
1422                                          "tools.shapes.star", "proportion", 0.5,
1423                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1424                                          0.01, 1.0, 0.01, 0.1,
1425                                          0, 0, 0, // labels2, values2, G_N_ELEMENTS(labels2),
1426                                          sp_stb_proportion_value_changed );
1427         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1428         g_object_set_data(G_OBJECT(holder), "prop_action", eact);
1430         if ( !isFlatSided ) {
1431             gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1432         } else {
1433             gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1434         }
1436         /* Roundedness */
1437         //gchar const* labels3[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1438         //gdouble values3[] = {-90, 0, 30, 90};
1439         eact = create_adjustment_action( "RoundednessAction",
1440                                          _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1441                                          "tools.shapes.star", "rounded", 0.0,
1442                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1443                                          -100.0, 100.0, 0.01, 0.1,
1444                                          0, 0, 0, // labels3, values3, G_N_ELEMENTS(labels3),
1445                                          sp_stb_rounded_value_changed );
1446         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1447         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1449         /* Randomization */
1450         //gchar const* labels4[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1451         //gdouble values4[] = {-90, 0, 30, 90};
1452         eact = create_adjustment_action( "RandomizationAction",
1453                                          _("Randomized:"), _("Scatter randomly the corners and angles"),
1454                                          "tools.shapes.star", "randomized", 0.0,
1455                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1456                                          -10.0, 10.0, 0.001, 0.01,
1457                                          0, 0, 0, // labels4, values4, G_N_ELEMENTS(labels4),
1458                                          sp_stb_randomized_value_changed, 0.1, 3 );
1459         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1460         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1461     }
1463     {
1464         /* Reset */
1465         {
1466             GtkAction* act = gtk_action_new( "ResetAction",
1467                                              _("Defaults"),
1468                                              _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1469                                              GTK_STOCK_CLEAR );
1470             g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1471             gtk_action_group_add_action( mainActions, act );
1472             gtk_action_set_sensitive( act, TRUE );
1473         }
1474     }
1477     GtkUIManager* mgr = gtk_ui_manager_new();
1478     GError* errVal = 0;
1480     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1481     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1483     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/StarToolbar" );
1484     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1485     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
1488     gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1490     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new stars"));
1491     swatch->setDesktop( desktop );
1492     swatch->setClickVerb( SP_VERB_CONTEXT_STAR_PREFS );
1493     swatch->setWatchedTool( "tools.shapes.star", true );
1494     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1495     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 );
1497     gtk_widget_show_all(holder);
1498     //sp_set_font_size_smaller (tbl);
1500     sigc::connection *connection = new sigc::connection(
1501         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GtkObject *)holder))
1502         );
1503     g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(delete_connection), connection);
1505     return holder;
1509 //########################
1510 //##       Rect         ##
1511 //########################
1513 static void
1514 sp_rtb_sensitivize (GtkWidget *tbl)
1516     GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "rx"));
1517     GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "ry"));
1518     GtkAction* not_rounded = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "not_rounded") );
1520     if (adj1->value == 0 && adj2->value == 0 && gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected rect (for now)
1521         gtk_action_set_sensitive( not_rounded, FALSE );
1522     } else {
1523         gtk_action_set_sensitive( not_rounded, TRUE );
1524     }
1528 static void
1529 sp_rtb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name,
1530                           void (*setter)(SPRect *, gdouble))
1532     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1534     UnitTracker* tracker = reinterpret_cast<UnitTracker*>(gtk_object_get_data(GTK_OBJECT(tbl), "tracker"));
1535     SPUnit const *unit = tracker->getActiveUnit();
1537     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1538         prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1539     }
1541     // quit if run by the attr_changed listener
1542     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1543         return;
1544     }
1546     // in turn, prevent listener from responding
1547     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1549     bool modmade = false;
1550     Inkscape::Selection *selection = sp_desktop_selection(desktop);
1551     for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1552         if (SP_IS_RECT(items->data)) {
1553             if (adj->value != 0) {
1554                 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1555             } else {
1556                 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1557             }
1558             modmade = true;
1559         }
1560     }
1562     sp_rtb_sensitivize (tbl);
1564     if (modmade) {
1565         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
1566                                    _("Change rectangle"));
1567     }
1569     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1571     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
1572     spinbutton_defocus(GTK_OBJECT(tbl));
1575 static void
1576 sp_rtb_rx_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1578     sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1581 static void
1582 sp_rtb_ry_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1584     sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1587 static void
1588 sp_rtb_width_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1590     sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1593 static void
1594 sp_rtb_height_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1596     sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1601 static void
1602 sp_rtb_defaults( GtkWidget *widget, GtkObject *obj)
1604     GtkWidget *tbl = GTK_WIDGET(obj);
1606     GtkAdjustment *adj = 0;
1608     adj = GTK_ADJUSTMENT( gtk_object_get_data(obj, "rx") );
1609     gtk_adjustment_set_value(adj, 0.0);
1610     // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1611     gtk_adjustment_value_changed(adj);
1613     adj = GTK_ADJUSTMENT( gtk_object_get_data(obj, "ry") );
1614     gtk_adjustment_set_value(adj, 0.0);
1615     gtk_adjustment_value_changed(adj);
1617     sp_rtb_sensitivize (tbl);
1620 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1621                                        gchar const *old_value, gchar const *new_value,
1622                                        bool is_interactive, gpointer data)
1624     GtkWidget *tbl = GTK_WIDGET(data);
1626     // quit if run by the _changed callbacks
1627     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1628         return;
1629     }
1631     // in turn, prevent callbacks from responding
1632     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1634     UnitTracker* tracker = reinterpret_cast<UnitTracker*>( gtk_object_get_data(GTK_OBJECT(tbl), "tracker") );
1635     SPUnit const *unit = tracker->getActiveUnit();
1637     gpointer item = g_object_get_data(G_OBJECT(tbl), "item");
1638     if (item && SP_IS_RECT(item)) {
1639         {
1640             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "rx");
1641             gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1642             gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1643         }
1645         {
1646             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "ry");
1647             gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1648             gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1649         }
1651         {
1652             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "width");
1653             gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1654             gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1655         }
1657         {
1658             GtkAdjustment *adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "height");
1659             gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1660             gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1661         }
1662     }
1664     sp_rtb_sensitivize (tbl);
1666     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1670 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1671     NULL, /* child_added */
1672     NULL, /* child_removed */
1673     rect_tb_event_attr_changed,
1674     NULL, /* content_changed */
1675     NULL  /* order_changed */
1676 };
1678 /**
1679  *  \param selection should not be NULL.
1680  */
1681 static void
1682 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
1684     int n_selected = 0;
1685     Inkscape::XML::Node *repr = NULL;
1686     SPItem *item = NULL;
1687     Inkscape::XML::Node *oldrepr = NULL;
1689     for (GSList const *items = selection->itemList();
1690          items != NULL;
1691          items = items->next) {
1692         if (SP_IS_RECT((SPItem *) items->data)) {
1693             n_selected++;
1694             item = (SPItem *) items->data;
1695             repr = SP_OBJECT_REPR(item);
1696         }
1697     }
1699     EgeOutputAction* act = EGE_OUTPUT_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "mode_action") );
1701     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
1703     if (n_selected == 0) {
1704         g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1706         GtkAction* w = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "width_action") );
1707         gtk_action_set_sensitive(w, FALSE);
1708         GtkAction* h = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "height_action") );
1709         gtk_action_set_sensitive(h, FALSE);
1711     } else if (n_selected == 1) {
1712         g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1713         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
1715         GtkAction* w = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "width_action") );
1716         gtk_action_set_sensitive(w, TRUE);
1717         GtkAction* h = GTK_ACTION( gtk_object_get_data(GTK_OBJECT(tbl), "height_action") );
1718         gtk_action_set_sensitive(h, TRUE);
1720         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
1721         if (oldrepr) { // remove old listener
1722             sp_repr_remove_listener_by_data(oldrepr, tbl);
1723             Inkscape::GC::release(oldrepr);
1724             oldrepr = 0;
1725             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
1726             g_object_set_data(G_OBJECT(tbl), "item", NULL);
1727         }
1728         if (repr) {
1729             g_object_set_data(G_OBJECT(tbl), "repr", repr);
1730             g_object_set_data(G_OBJECT(tbl), "item", item);
1731             Inkscape::GC::anchor(repr);
1732             sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1733             sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1734         }
1735     } else {
1736         // FIXME: implement averaging of all parameters for multiple selected
1737         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1738         g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1739         sp_rtb_sensitivize (GTK_WIDGET(tbl));
1740     }
1744 static GtkWidget *
1745 sp_rect_toolbox_new(SPDesktop *desktop)
1747     GtkWidget *holder = gtk_hbox_new(FALSE, 0);
1748     gtk_object_set_data(GTK_OBJECT(holder), "dtw", desktop->canvas);
1749     gtk_object_set_data(GTK_OBJECT(holder), "desktop", desktop);
1751     gchar const * descr =
1752         "<ui>"
1753         "  <toolbar name='RectToolbar'>"
1754         "    <toolitem action='RectStateAction' />"
1755         "    <toolitem action='WidthAction' />"
1756         "    <toolitem action='HeightAction' />"
1757         "    <toolitem action='RadiusXAction' />"
1758         "    <toolitem action='RadiusYAction' />"
1759         "    <toolitem action='RectUnitsAction' />"
1760         "    <separator />"
1761         "    <toolitem action='RectResetAction' />"
1762         "  </toolbar>"
1763         "</ui>";
1764     GtkActionGroup* mainActions = gtk_action_group_new("main");
1766     EgeAdjustmentAction* eact = 0;
1768     {
1769         EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
1770         ege_output_action_set_use_markup( act, TRUE );
1771         gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1772         gtk_object_set_data( GTK_OBJECT(holder), "mode_action", act );
1773     }
1775     // rx/ry units menu: create
1776     UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1777     //tracker->addUnit( SP_UNIT_PERCENT, 0 );
1778     // fixme: add % meaning per cent of the width/height
1779     tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1780     gtk_object_set_data( GTK_OBJECT(holder), "tracker", tracker );
1782     /* W */
1783     {
1784         eact = create_adjustment_action( "WidthAction",
1785                                          _("W:"), _("Width of rectangle"),
1786                                          "tools.shapes.rect", "width", 0,
1787                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
1788                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1789                                          0, 0, 0,
1790                                          sp_rtb_width_value_changed );
1791         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1792         gtk_object_set_data( GTK_OBJECT(holder), "width_action", eact );
1793         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1794         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1795     }
1797     /* H */
1798     {
1799         eact = create_adjustment_action( "HeightAction",
1800                                          _("H:"), _("Height of rectangle"),
1801                                          "tools.shapes.rect", "height", 0,
1802                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1803                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1804                                          0, 0, 0,
1805                                          sp_rtb_height_value_changed );
1806         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1807         gtk_object_set_data( GTK_OBJECT(holder), "height_action", eact );
1808         gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1809         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1810     }
1812     /* rx */
1813     {
1814         eact = create_adjustment_action( "RadiusXAction",
1815                                          _("Rx:"), _("Horizontal radius of rounded corners"),
1816                                          "tools.shapes.rect", "rx", 0,
1817                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1818                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1819                                          0, 0, 0,
1820                                          sp_rtb_rx_value_changed);
1821         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1822         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1823     }
1825     /* ry */
1826     {
1827         eact = create_adjustment_action( "RadiusYAction",
1828                                          _("Ry:"), _("Vertical radius of rounded corners"),
1829                                          "tools.shapes.rect", "ry", 0,
1830                                          GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1831                                          0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1832                                          0, 0, 0,
1833                                          sp_rtb_ry_value_changed);
1834         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1835         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1836     }
1838     // add the units menu
1839     {
1840         GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), _("") );
1841         gtk_action_group_add_action( mainActions, act );
1842     }
1844     /* Reset */
1845     {
1846         InkAction* inky = ink_action_new( "RectResetAction",
1847                                           _("Not rounded"),
1848                                           _("Make corners sharp"),
1849                                           "squared_corner",
1850                                           Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1851         g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
1852         gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1853         gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
1854         gtk_object_set_data( GTK_OBJECT(holder), "not_rounded", inky );
1855     }
1857     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new rectangles"));
1858     swatch->setDesktop (desktop);
1859     swatch->setClickVerb (SP_VERB_CONTEXT_RECT_PREFS);
1860     swatch->setWatchedTool ("tools.shapes.rect", true);
1861     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
1862     gtk_box_pack_end(GTK_BOX(holder), swatch_, FALSE, FALSE, 0);
1864     g_object_set_data(G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE));
1865     sp_rtb_sensitivize (holder);
1868     GtkUIManager* mgr = gtk_ui_manager_new();
1869     GError* errVal = 0;
1871     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1872     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1874     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/RectToolbar" );
1875     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1876     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
1879     gtk_box_pack_start( GTK_BOX(holder), toolBar, TRUE, TRUE, 0 );
1882     gtk_widget_show_all(holder);
1883     sp_set_font_size_smaller(holder);
1885     sigc::connection *connection = new sigc::connection(
1886         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GtkObject *)holder))
1887         );
1888     g_signal_connect(G_OBJECT(holder), "destroy", G_CALLBACK(delete_connection), connection);
1890     return holder;
1893 //########################
1894 //##       Spiral       ##
1895 //########################
1897 static void
1898 sp_spl_tb_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name)
1900     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
1902     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1903         prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
1904     }
1906     // quit if run by the attr_changed listener
1907     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1908         return;
1909     }
1911     // in turn, prevent listener from responding
1912     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1914     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
1916     bool modmade = false;
1917     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
1918          items != NULL;
1919          items = items->next)
1920     {
1921         if (SP_IS_SPIRAL((SPItem *) items->data)) {
1922             Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1923             sp_repr_set_svg_double( repr, namespaced_name, adj->value );
1924             SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1925             modmade = true;
1926         }
1927     }
1929     g_free(namespaced_name);
1931     if (modmade) {
1932         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
1933                                    _("Change spiral"));
1934     }
1936     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1938     spinbutton_defocus(GTK_OBJECT(tbl));
1941 static void
1942 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1944     sp_spl_tb_value_changed(adj, tbl, "revolution");
1947 static void
1948 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1950     sp_spl_tb_value_changed(adj, tbl, "expansion");
1953 static void
1954 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
1956     sp_spl_tb_value_changed(adj, tbl, "t0");
1959 static void
1960 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
1962     GtkWidget *tbl = GTK_WIDGET(obj);
1964     GtkAdjustment *adj;
1966     // fixme: make settable
1967     gdouble rev = 5;
1968     gdouble exp = 1.0;
1969     gdouble t0 = 0.0;
1971     adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
1972     gtk_adjustment_set_value(adj, rev);
1973     gtk_adjustment_value_changed(adj);
1975     adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
1976     gtk_adjustment_set_value(adj, exp);
1977     gtk_adjustment_value_changed(adj);
1979     adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
1980     gtk_adjustment_set_value(adj, t0);
1981     gtk_adjustment_value_changed(adj);
1983     spinbutton_defocus(GTK_OBJECT(tbl));
1987 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1988                                          gchar const *old_value, gchar const *new_value,
1989                                          bool is_interactive, gpointer data)
1991     GtkWidget *tbl = GTK_WIDGET(data);
1993     // quit if run by the _changed callbacks
1994     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1995         return;
1996     }
1998     // in turn, prevent callbacks from responding
1999     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2001     GtkAdjustment *adj;
2002     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2003     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2005     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2006     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2008     adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2009     gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2011     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2015 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2016     NULL, /* child_added */
2017     NULL, /* child_removed */
2018     spiral_tb_event_attr_changed,
2019     NULL, /* content_changed */
2020     NULL  /* order_changed */
2021 };
2023 static void
2024 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2026     int n_selected = 0;
2027     Inkscape::XML::Node *repr = NULL;
2028     Inkscape::XML::Node *oldrepr = NULL;
2030     for (GSList const *items = selection->itemList();
2031          items != NULL;
2032          items = items->next)
2033     {
2034         if (SP_IS_SPIRAL((SPItem *) items->data)) {
2035             n_selected++;
2036             repr = SP_OBJECT_REPR((SPItem *) items->data);
2037         }
2038     }
2040     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2042     if (n_selected == 0) {
2043         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2044     } else if (n_selected == 1) {
2045         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2047         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2048         if (oldrepr) { // remove old listener
2049             sp_repr_remove_listener_by_data(oldrepr, tbl);
2050             Inkscape::GC::release(oldrepr);
2051             oldrepr = 0;
2052             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2053         }
2055         if (repr) {
2056             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2057             Inkscape::GC::anchor(repr);
2058             sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2059             sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2060         }
2061     } else {
2062         // FIXME: implement averaging of all parameters for multiple selected
2063         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2064         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2065     }
2069 static GtkWidget *
2070 sp_spiral_toolbox_new(SPDesktop *desktop)
2072     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2073     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2074     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2076     GtkTooltips *tt = gtk_tooltips_new();
2078     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2080     /* Revolution */
2081     {
2082         GtkWidget *hb = sp_tb_spinbutton(_("Turns:"), _("Number of revolutions"),
2083                                          "tools.shapes.spiral", "revolution", 3.0,
2084                                          NULL, tbl, TRUE, "altx-spiral",
2085                                          0.01, 1024.0, 0.1, 1.0,
2086                                          sp_spl_tb_revolution_value_changed, 1, 2);
2087         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2088     }
2090     /* Expansion */
2091     {
2092         GtkWidget *hb = sp_tb_spinbutton(_("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2093                                          "tools.shapes.spiral", "expansion", 1.0,
2094                                          NULL, tbl, FALSE, NULL,
2095                                          0.0, 1000.0, 0.01, 1.0,
2096                                          sp_spl_tb_expansion_value_changed);
2097         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2098     }
2100     /* T0 */
2101     {
2102         GtkWidget *hb = sp_tb_spinbutton(_("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2103                                          "tools.shapes.spiral", "t0", 0.0,
2104                                          NULL, tbl, FALSE, NULL,
2105                                          0.0, 0.999, 0.01, 1.0,
2106                                          sp_spl_tb_t0_value_changed);
2107         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_SPACING);
2108     }
2110     aux_toolbox_space(tbl, AUX_SPACING);
2112     /* Reset */
2113     {
2114         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2115         GtkWidget *b = gtk_button_new_with_label(_("Defaults"));
2116         gtk_tooltips_set_tip(tt, b, _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"), NULL);
2117         gtk_widget_show(b);
2118         gtk_container_add(GTK_CONTAINER(hb), b);
2119         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_spl_tb_defaults), tbl);
2120         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2121     }
2123     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new spirals"));
2124     swatch->setDesktop (desktop);
2125     swatch->setClickVerb (SP_VERB_CONTEXT_SPIRAL_PREFS);
2126     swatch->setWatchedTool ("tools.shapes.spiral", true);
2127     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2128     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2130     gtk_widget_show_all(tbl);
2131     sp_set_font_size_smaller (tbl);
2133     sigc::connection *connection = new sigc::connection(
2134         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GtkObject *)tbl))
2135         );
2136     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2138     return tbl;
2141 //########################
2142 //##     Pen/Pencil    ##
2143 //########################
2146 static GtkWidget *
2147 sp_pen_toolbox_new(SPDesktop *desktop)
2149     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2150     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2151     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2153     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new paths created by Pen"));
2154     swatch->setDesktop (desktop);
2155     swatch->setClickVerb (SP_VERB_CONTEXT_PEN_PREFS);
2156     swatch->setWatchedTool ("tools.freehand.pen", true);
2157     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2158     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2160     gtk_widget_show_all(tbl);
2161     sp_set_font_size_smaller (tbl);
2163     return tbl;
2166 static GtkWidget *
2167 sp_pencil_toolbox_new(SPDesktop *desktop)
2169     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2170     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2171     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2173     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new paths created by Pencil"));
2174     swatch->setDesktop (desktop);
2175     swatch->setClickVerb (SP_VERB_CONTEXT_PENCIL_PREFS);
2176     swatch->setWatchedTool ("tools.freehand.pencil", true);
2177     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2178     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2180     gtk_widget_show_all(tbl);
2181     sp_set_font_size_smaller (tbl);
2183     return tbl;
2187 //########################
2188 //##     Calligraphy    ##
2189 //########################
2191 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2193     prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
2196 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2198     prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
2201 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2203     prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
2206 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2208     prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
2211 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2213     prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
2216 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2218     prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
2221 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2223     prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
2226 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GtkWidget *tbl )
2228     prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
2231 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer data )
2233     prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2236 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer data )
2238     prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
2241 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
2243     prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2245     gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
2248 static void sp_ddc_defaults(GtkWidget *, GtkWidget *dataKludge)
2250     // FIXME: make defaults settable via Inkscape Options
2251     struct KeyValue {
2252         char const *key;
2253         double value;
2254     } const key_values[] = {
2255         {"mass", 0.02},
2256         {"wiggle", 0.0},
2257         {"angle", 30.0},
2258         {"width", 15},
2259         {"thinning", 0.1},
2260         {"tremor", 0.0},
2261         {"flatness", 0.9},
2262         {"cap_rounding", 0.0}
2263     };
2265     for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2266         KeyValue const &kv = key_values[i];
2267         GtkAdjustment* adj = static_cast<GtkAdjustment *>(gtk_object_get_data(GTK_OBJECT(dataKludge), kv.key));
2268         if ( adj ) {
2269             gtk_adjustment_set_value(adj, kv.value);
2270         }
2271     }
2275 static GtkWidget *
2276 sp_calligraphy_toolbox_new(SPDesktop *desktop)
2278     GtkWidget* holder = gtk_table_new( 1, 2, FALSE );
2280     gchar const * descr =
2281         "<ui>"
2282         "  <toolbar name='CalligraphyToolbar'>"
2283         "    <separator />"
2284         "    <toolitem name='Width' action='WidthAction' />"
2285         "    <toolitem name='Thinning' action='ThinningAction' />"
2286         "    <separator />"
2287         "    <toolitem name='Angle' action='AngleAction' />"
2288         "    <toolitem action='FixationAction' />"
2289         "    <toolitem action='CapRoundingAction' />"
2290         "    <separator />"
2291         "    <toolitem action='TremorAction' />"
2292         "    <toolitem action='WiggleAction' />"
2293         "    <toolitem action='MassAction' />"
2294         "    <separator />"
2295         "    <toolitem action='TraceAction' />"
2296         "    <toolitem action='PressureAction' />"
2297         "    <toolitem action='TiltAction' />"
2298         "    <toolitem action='ResetAction' />"
2299         "  </toolbar>"
2300         "</ui>";
2301     GtkActionGroup* mainActions = gtk_action_group_new("main");
2303     {
2304         EgeAdjustmentAction* calligraphy_angle = 0;
2306         {
2307         /* Width */
2308         gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
2309         gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2310         EgeAdjustmentAction *eact = create_adjustment_action( "WidthAction",
2311                                          _("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2312                                          "tools.calligraphic", "width", 15,
2313                                          GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
2314                                          1, 100, 1.0, 10.0,
2315                                          labels, values, G_N_ELEMENTS(labels),
2316                                          sp_ddc_width_value_changed,  0.01, 0, 100 );
2317         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2318         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2319         }
2321         {
2322         /* Thinning */
2323             gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
2324             gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
2325         EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
2326                                          _("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2327                                          "tools.calligraphic", "thinning", 0.1,
2328                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2329                                          -1.0, 1.0, 0.01, 0.1,
2330                                          labels, values, G_N_ELEMENTS(labels),
2331                                          sp_ddc_velthin_value_changed, 0.01, 2);
2332         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2333         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2334         }
2336         {
2337         /* Angle */
2338         gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
2339         gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2340         EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
2341                                          _("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2342                                          "tools.calligraphic", "angle", 30,
2343                                          GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
2344                                          -90.0, 90.0, 1.0, 10.0,
2345                                          labels, values, G_N_ELEMENTS(labels),
2346                                          sp_ddc_angle_value_changed, 1, 0 );
2347         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2348         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2349         calligraphy_angle = eact;
2350         }
2352         {
2353         /* Fixation */
2354             gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
2355         gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
2356         EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
2357                                          _("Fixation:"), _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
2358                                          "tools.calligraphic", "flatness", 0.9,
2359                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2360                                          0.0, 1.0, 0.01, 0.1,
2361                                          labels, values, G_N_ELEMENTS(labels),
2362                                          sp_ddc_flatness_value_changed, 0.01, 2 );
2363         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2364         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2365         }
2367         {
2368         /* Cap Rounding */
2369             gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
2370         gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
2371         // TRANSLATORS: "cap" means "end" (both start and finish) here
2372         EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
2373                                          _("Caps:"), _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
2374                                          "tools.calligraphic", "cap_rounding", 0.0,
2375                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2376                                          0.0, 5.0, 0.01, 0.1,
2377                                          labels, values, G_N_ELEMENTS(labels),
2378                                          sp_ddc_cap_rounding_value_changed, 0.01, 2 );
2379         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2380         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2381         }
2383         {
2384         /* Tremor */
2385             gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
2386         gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
2387         EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
2388                                          _("Tremor:"), _("Increase to make strokes rugged and trembling"),
2389                                          "tools.calligraphic", "tremor", 0.0,
2390                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2391                                          0.0, 1.0, 0.01, 0.1,
2392                                          labels, values, G_N_ELEMENTS(labels),
2393                                          sp_ddc_tremor_value_changed, 0.01, 2 );
2395         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2396         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2397         }
2399         {
2400         /* Wiggle */
2401         gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
2402         gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
2403         EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
2404                                          _("Wiggle:"), _("Increase to make the pen waver and wiggle"),
2405                                          "tools.calligraphic", "wiggle", 0.0,
2406                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2407                                          0.0, 1.0, 0.01, 0.1,
2408                                          labels, values, G_N_ELEMENTS(labels),
2409                                          sp_ddc_wiggle_value_changed, 0.01, 2 );
2410         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2411         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2412         }
2414         {
2415         /* Mass */
2416             gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
2417         gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
2418         EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
2419                                          _("Mass:"), _("Increase to make the pen drag behind, as if slowed by inertia"),
2420                                          "tools.calligraphic", "mass", 0.02,
2421                                          GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2422                                          0.0, 1.0, 0.01, 0.1,
2423                                          labels, values, G_N_ELEMENTS(labels),
2424                                          sp_ddc_mass_value_changed, 0.01, 2 );
2425         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2426         gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2427         }
2430         /* Trace Background button */
2431         {
2432             InkToggleAction* act = ink_toggle_action_new( "TraceAction",
2433                                                           _("Trace Background"),
2434                                                           _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
2435                                                           "trace_background",
2436                                                           Inkscape::ICON_SIZE_DECORATION );
2437             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2438             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
2439             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
2440         }
2442         /* Use Pressure button */
2443         {
2444             InkToggleAction* act = ink_toggle_action_new( "PressureAction",
2445                                                           _("Pressure"),
2446                                                           _("Use the pressure of the input device to alter the width of the pen"),
2447                                                           "use_pressure",
2448                                                           Inkscape::ICON_SIZE_DECORATION );
2449             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2450             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
2451             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
2452         }
2454         /* Use Tilt button */
2455         {
2456             InkToggleAction* act = ink_toggle_action_new( "TiltAction",
2457                                                           _("Tilt"),
2458                                                           _("Use the tilt of the input device to alter the angle of the pen's nib"),
2459                                                           "use_tilt",
2460                                                           Inkscape::ICON_SIZE_DECORATION );
2461             gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2462             g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
2463             gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2464             gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2465         }
2467         /* Reset */
2468         {
2469             GtkAction* act = gtk_action_new( "ResetAction",
2470                                              _("Defaults"),
2471                                              _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2472                                              GTK_STOCK_CLEAR );
2473             g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
2474             gtk_action_group_add_action( mainActions, act );
2475             gtk_action_set_sensitive( act, TRUE );
2476         }
2477     }
2480     GtkUIManager* mgr = gtk_ui_manager_new();
2481     GError* errVal = 0;
2483     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
2484     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
2486     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CalligraphyToolbar" );
2487     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
2488     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
2491     gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
2493     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new calligraphic strokes"));
2494     swatch->setDesktop (desktop);
2495     swatch->setClickVerb (SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS);
2496     swatch->setWatchedTool ("tools.calligraphic", true);
2497     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2498     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 );
2500     gtk_widget_show_all(holder);
2501     //sp_set_font_size_smaller (tbl);
2503     return holder;
2507 //########################
2508 //##    Circle / Arc    ##
2509 //########################
2511 static void
2512 sp_arctb_sensitivize (GtkWidget *tbl, double v1, double v2)
2514     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2515     GtkWidget *make_whole = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "make_whole");
2517     if (v1 == 0 && v2 == 0) {
2518         if (gtk_object_get_data(GTK_OBJECT(tbl), "single")) { // only for a single selected ellipse (for now)
2519             gtk_widget_set_sensitive(GTK_WIDGET(ocb), FALSE);
2520             gtk_widget_set_sensitive(GTK_WIDGET(make_whole), FALSE);
2521         }
2522     } else {
2523         gtk_widget_set_sensitive(GTK_WIDGET(ocb), TRUE);
2524         gtk_widget_set_sensitive(GTK_WIDGET(make_whole), TRUE);
2525     }
2528 static void
2529 sp_arctb_startend_value_changed(GtkAdjustment *adj, GtkWidget *tbl, gchar const *value_name, gchar const *other_name)
2531     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2533     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2534         prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2535     }
2537     // quit if run by the attr_changed listener
2538     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2539         return;
2540     }
2542     // in turn, prevent listener from responding
2543     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2545     gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2547     bool modmade = false;
2548     for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2549          items != NULL;
2550          items = items->next)
2551     {
2552         SPItem *item = SP_ITEM(items->data);
2554         if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2556             SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2557             SPArc *arc = SP_ARC(item);
2559             if (!strcmp(value_name, "start"))
2560                 ge->start = (adj->value * M_PI)/ 180;
2561             else
2562                 ge->end = (adj->value * M_PI)/ 180;
2564             sp_genericellipse_normalize(ge);
2565             ((SPObject *)arc)->updateRepr();
2566             ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2568             modmade = true;
2569         }
2570     }
2572     g_free(namespaced_name);
2574     GtkAdjustment *other = (GtkAdjustment *)gtk_object_get_data(GTK_OBJECT(tbl), other_name);
2576     sp_arctb_sensitivize (tbl, adj->value, other->value);
2578     if (modmade) {
2579         sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
2580                                    _("Arc: Change start/end"));
2581     }
2583     // defocus spinbuttons by moving focus to the canvas, unless "stay" is on
2584     spinbutton_defocus(GTK_OBJECT(tbl));
2586     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2590 static void
2591 sp_arctb_start_value_changed(GtkAdjustment *adj,  GtkWidget *tbl)
2593     sp_arctb_startend_value_changed(adj,  tbl, "start", "end");
2596 static void
2597 sp_arctb_end_value_changed(GtkAdjustment *adj, GtkWidget *tbl)
2599     sp_arctb_startend_value_changed(adj,  tbl, "end", "start");
2602 static void
2603 sp_arctb_open_state_changed(GtkWidget *widget, GtkObject *tbl)
2605     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2607     if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2608         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2609             prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2610         } else {
2611             prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2612         }
2613     }
2615     // quit if run by the attr_changed listener
2616     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2617         return;
2618     }
2620     // in turn, prevent listener from responding
2621     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2623     bool modmade = false;
2625     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
2626         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2627              items != NULL;
2628              items = items->next)
2629         {
2630             if (SP_IS_ARC((SPItem *) items->data)) {
2631                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2632                 repr->setAttribute("sodipodi:open", "true");
2633                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2634                 modmade = true;
2635             }
2636         }
2637     } else {
2638         for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2639              items != NULL;
2640              items = items->next)
2641         {
2642             if (SP_IS_ARC((SPItem *) items->data))    {
2643                 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2644                 repr->setAttribute("sodipodi:open", NULL);
2645                 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2646                 modmade = true;
2647             }
2648         }
2649     }
2651     if (modmade) {
2652         sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
2653                                    _("Arc: Change open/closed"));
2654     }
2656     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2658     spinbutton_defocus(GTK_OBJECT(tbl));
2661 static void sp_arctb_defaults(GtkWidget *, GtkObject *obj)
2663     GtkWidget *tbl = GTK_WIDGET(obj);
2665     GtkAdjustment *adj;
2666     adj = (GtkAdjustment*)gtk_object_get_data(obj, "start");
2667     gtk_adjustment_set_value(adj, 0.0);
2668     gtk_adjustment_value_changed(adj);
2670     adj = (GtkAdjustment*)gtk_object_get_data(obj, "end");
2671     gtk_adjustment_set_value(adj, 0.0);
2672     gtk_adjustment_value_changed(adj);
2674     spinbutton_defocus(GTK_OBJECT(tbl));
2677 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2678                                       gchar const *old_value, gchar const *new_value,
2679                                       bool is_interactive, gpointer data)
2681     GtkWidget *tbl = GTK_WIDGET(data);
2683     // quit if run by the _changed callbacks
2684     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2685         return;
2686     }
2688     // in turn, prevent callbacks from responding
2689     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2691     gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2692     gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2694     GtkAdjustment *adj1,*adj2;
2695     adj1 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "start");
2696     gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2697     adj2 = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "end");
2698     gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2700     sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2702     char const *openstr = NULL;
2703     openstr = repr->attribute("sodipodi:open");
2704     GtkWidget *ocb = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "open_checkbox");
2706     if (openstr) {
2707         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  TRUE);
2708     } else {
2709         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(ocb),  FALSE);
2710     }
2712     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2715 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2716     NULL, /* child_added */
2717     NULL, /* child_removed */
2718     arc_tb_event_attr_changed,
2719     NULL, /* content_changed */
2720     NULL  /* order_changed */
2721 };
2724 static void
2725 sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GtkObject *tbl)
2727     int n_selected = 0;
2728     Inkscape::XML::Node *repr = NULL;
2729     Inkscape::XML::Node *oldrepr = NULL;
2731     for (GSList const *items = selection->itemList();
2732          items != NULL;
2733          items = items->next)
2734     {
2735         if (SP_IS_ARC((SPItem *) items->data)) {
2736             n_selected++;
2737             repr = SP_OBJECT_REPR((SPItem *) items->data);
2738         }
2739     }
2741     GtkWidget *l = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(tbl), "mode_label"));
2743     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(FALSE));
2744     if (n_selected == 0) {
2745         gtk_label_set_markup(GTK_LABEL(l), _("<b>New:</b>"));
2746     } else if (n_selected == 1) {
2747         g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2748         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2750         oldrepr = (Inkscape::XML::Node *) gtk_object_get_data(GTK_OBJECT(tbl), "repr");
2752         if (oldrepr) { // remove old listener
2753             sp_repr_remove_listener_by_data(oldrepr, tbl);
2754             Inkscape::GC::release(oldrepr);
2755             oldrepr = 0;
2756             g_object_set_data(G_OBJECT(tbl), "repr", NULL);
2757         }
2759         if (repr) {
2760             g_object_set_data(G_OBJECT(tbl), "repr", repr);
2761             Inkscape::GC::anchor(repr);
2762             sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2763             sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2764         }
2765     } else {
2766         // FIXME: implement averaging of all parameters for multiple selected
2767         //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2768         gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2769         sp_arctb_sensitivize (GTK_WIDGET(tbl), 1, 0);
2770     }
2774 static GtkWidget *
2775 sp_arc_toolbox_new(SPDesktop *desktop)
2777     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2779     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2780     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2782     GtkTooltips *tt = gtk_tooltips_new();
2784     sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2786     /* Start */
2787     {
2788         GtkWidget *hb = sp_tb_spinbutton(_("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2789                                          "tools.shapes.arc", "start", 0.0,
2790                                          NULL, tbl, TRUE, "altx-arc",
2791                                          -360.0, 360.0, 1.0, 10.0,
2792                                          sp_arctb_start_value_changed);
2793         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2794     }
2796     /* End */
2797     {
2798         GtkWidget *hb = sp_tb_spinbutton(_("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2799                                          "tools.shapes.arc", "end", 0.0,
2800                                          NULL, tbl, FALSE, NULL,
2801                                          -360.0, 360.0, 1.0, 10.0,
2802                                          sp_arctb_end_value_changed);
2803         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2804     }
2806     /* Segments / Pie checkbox */
2807     {
2808         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2809         GtkWidget *fscb = gtk_check_button_new_with_label(_("Open arc"));
2810         gtk_tooltips_set_tip(tt, fscb, _("Switch between arc (unclosed shape) and segment (closed shape with two radii)"), NULL);
2812         gchar const *openstr = NULL;
2813         openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2814         if (!openstr || (openstr && !strcmp(openstr, "false")))
2815             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  FALSE);
2816         else
2817             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(fscb),  TRUE);
2819         gtk_widget_show(fscb);
2820         gtk_object_set_data(GTK_OBJECT(tbl), "open_checkbox", fscb);
2821         gtk_container_add(GTK_CONTAINER(hb), fscb);
2822         g_signal_connect(G_OBJECT(fscb), "toggled", GTK_SIGNAL_FUNC(sp_arctb_open_state_changed ), tbl);
2823         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2824     }
2826     /* Make Whole */
2827     {
2828         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2829         GtkWidget *b = gtk_button_new_with_label(_("Make whole"));
2830         gtk_object_set_data(GTK_OBJECT(tbl), "make_whole", b);
2831         gtk_tooltips_set_tip(tt, b, _("Make the shape a whole ellipse, not arc or segment"), NULL);
2832         gtk_widget_show(b);
2833         gtk_container_add(GTK_CONTAINER(hb), b);
2834         gtk_signal_connect(GTK_OBJECT(b), "clicked", GTK_SIGNAL_FUNC(sp_arctb_defaults), tbl);
2835         gtk_box_pack_start(GTK_BOX(tbl),hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
2836     }
2838     g_object_set_data(G_OBJECT(tbl), "single", GINT_TO_POINTER(TRUE));
2839     // sensitivize make whole and open checkbox
2840     {
2841         GtkAdjustment *adj1 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "start"));
2842         GtkAdjustment *adj2 = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "end"));
2843         sp_arctb_sensitivize (tbl, adj1->value, adj2->value);
2844     }
2846     sigc::connection *connection = new sigc::connection(
2847         sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GtkObject *)tbl))
2848         );
2849     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection), connection);
2851     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of new ellipses"));
2852     swatch->setDesktop (desktop);
2853     swatch->setClickVerb (SP_VERB_CONTEXT_ARC_PREFS);
2854     swatch->setWatchedTool ("tools.shapes.arc", true);
2855     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
2856     gtk_box_pack_end(GTK_BOX(tbl), swatch_, FALSE, FALSE, 0);
2858     gtk_widget_show_all(tbl);
2859     sp_set_font_size_smaller (tbl);
2861     return tbl;
2867 // toggle button callbacks and updaters
2869 //########################
2870 //##      Dropper       ##
2871 //########################
2873 static void toggle_dropper_pick_alpha (GtkWidget *button, gpointer tbl) {
2874     prefs_set_int_attribute ("tools.dropper", "pick",
2875         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
2876     GtkWidget *set_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "set_checkbox");
2877     if (set_checkbox) {
2878         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
2879             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), TRUE);
2880         } else {
2881             gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), FALSE);
2882         }
2883     }
2884     spinbutton_defocus(GTK_OBJECT(tbl));
2887 static void toggle_dropper_set_alpha (GtkWidget *button, gpointer tbl) {
2888     prefs_set_int_attribute ("tools.dropper", "setalpha",
2889         gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
2890     spinbutton_defocus(GTK_OBJECT(tbl));
2894 /**
2895  * Copy the current saved desktop color to the clipboard as full hex + alpha
2896  * color representation. This is useful for passing values between various
2897  * input boxes, or directly to xml.
2898  */
2899 /* static void
2900 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2902     GtkWidget *tbl = GTK_WIDGET(obj);
2904     SPDesktop *desktop =
2905         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2908     sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2909 }*/
2912 /**
2913  * Copies currently saved desktop color to the clipboard as a hex value. This
2914  * is useful for editing webpages and needing a value quickly for web
2915  * colors.
2916  *
2917  * TODO: When the toggle of the dropper is set to not mix color against
2918  *       page background, this still just gets the color of the page and
2919  *       doesn't get the actual mixed against background which is needed
2920  *       for the hex value ppl. want for web pages, etc.
2921  */
2923 /* static void
2924 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2926     GtkWidget *tbl = GTK_WIDGET(obj);
2928     SPDesktop *desktop =
2929         (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2931     sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2932 }*/
2935 /**
2936  * Sets the input boxes with the changed color and opacity. This is used as a
2937  * callback for style changing.
2938  */
2939 /* static bool
2940 sp_style_changed (const SPCSSAttr *css, gpointer data)
2942     // GrDrag *drag = (GrDrag *) data;
2944     // set fill of text entry box
2945     if (css->attribute("fill"))
2946         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2947             css->attribute("fill"));
2949     // set opacity of text entry box
2950     if (css->attribute("fill-opacity"))
2951         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2952             css->attribute("fill-opacity"));
2954     // set fill of text entry box
2955     if (css->attribute("stroke"))
2956         gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2957             css->attribute("stroke"));
2959     // set opacity of text entry box
2960     if (css->attribute("stroke-opacity"))
2961         gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
2962             css->attribute("stroke-opacity"));
2963     return false;
2966 */
2969 /**
2970  * Dropper auxiliary toolbar construction and setup.
2971  *
2972  * TODO: Would like to add swatch of current color.
2973  * TODO: Add queue of last 5 or so colors selected with new swatches so that
2974  *       can drag and drop places. Will provide a nice mixing palette.
2975  */
2976 static GtkWidget *
2977 sp_dropper_toolbox_new(SPDesktop *desktop)
2979     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
2981     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2982     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2984     GtkTooltips *tt = gtk_tooltips_new();
2987     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
2988                        AUX_BETWEEN_BUTTON_GROUPS);
2989     // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
2993     /* RGB Input Field */
2994  /*   {
2995         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
2996         GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
2997         gtk_widget_show (dropper_rgba_label);
2998         gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
3000         dropper_rgb_entry = gtk_entry_new ();
3001         sp_dialog_defocus_on_enter (dropper_rgb_entry);
3002         gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
3003         gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
3004         gtk_tooltips_set_tip(tt, dropper_rgb_entry,
3005                          _("Hexidecimal representation of last selected "
3006                            "color"),
3007                          NULL);
3008         gtk_widget_show (dropper_rgb_entry);
3009         gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
3011         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3012                            AUX_BETWEEN_BUTTON_GROUPS);
3013     } */
3015     /* Opacity Input Field */
3016 /*    {
3017         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3018         GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
3019         gtk_widget_show (dropper_opacity_label);
3020         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
3022         dropper_opacity_entry = gtk_entry_new ();
3023         sp_dialog_defocus_on_enter (dropper_opacity_entry);
3024         gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
3025         gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
3026         gtk_tooltips_set_tip(tt, dropper_opacity_entry,
3027                          _("Opacity of last selected color"),
3028                          NULL);
3029         gtk_widget_show (dropper_opacity_entry);
3030         gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
3032         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3033                            AUX_BETWEEN_BUTTON_GROUPS);
3034     } */
3037     /* Copy to Clipboard */
3038 /*    {
3039         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3040         GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
3041         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
3042                                       "RGB + Alpha (RGBA) to "
3043                                       "clipboard"),
3044                              NULL);
3045         gtk_widget_show(b);
3046         gtk_container_add(GTK_CONTAINER(hb), b);
3047         gtk_signal_connect(GTK_OBJECT(b), "clicked",
3048             GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
3049         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3050                            AUX_BETWEEN_BUTTON_GROUPS);
3051     } */
3054     /* Copy to Clipboard as HEX */
3055 /*    {
3056         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3057         GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
3058         gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
3059                                       "hexidecimal RGB without alpha "
3060                                       "to clipboard"), NULL);
3061         gtk_widget_show(b);
3062         gtk_container_add(GTK_CONTAINER(hb), b);
3063         gtk_signal_connect(GTK_OBJECT(b), "clicked",
3064             GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
3065         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3066                            AUX_BETWEEN_BUTTON_GROUPS);
3067     } */
3069     // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3071     {
3072         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3074         GtkWidget *button = gtk_check_button_new_with_label(_("Pick alpha"));
3075         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);
3076         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
3077                                       prefs_get_int_attribute ("tools.dropper",
3078                                                                "pick", 1));
3079         gtk_widget_show(button);
3080         gtk_container_add (GTK_CONTAINER (hb), button);
3081         gtk_object_set_data(GTK_OBJECT(tbl), "pick_checkbox", button);
3082         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_pick_alpha), tbl);
3083         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3084                    AUX_BETWEEN_BUTTON_GROUPS);
3085     }
3087     {
3088         GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3090         GtkWidget *button = gtk_check_button_new_with_label(_("Set alpha"));
3091         gtk_tooltips_set_tip(tt, button, _("If alpha was picked, assign it to selection as fill or stroke transparency"), NULL);
3092         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
3093                                       prefs_get_int_attribute ("tools.dropper",
3094                                                                "setalpha", 1));
3095         gtk_widget_show(button);
3096         gtk_container_add (GTK_CONTAINER (hb), button);
3097         gtk_object_set_data(GTK_OBJECT(tbl), "set_checkbox", button);
3098         g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_set_alpha), tbl);
3100         // make sure it's disabled if we're not picking alpha
3101         GtkWidget *pick_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "pick_checkbox");
3102         if (pick_checkbox) {
3103             if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pick_checkbox))) {
3104                 gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
3105             } else {
3106                 gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
3107             }
3108         }
3110         gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3111                    AUX_BETWEEN_BUTTON_GROUPS);
3112     }
3114     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3117     // where new gtkmm stuff should go
3119     gtk_widget_show_all(tbl);
3120     sp_set_font_size_smaller (tbl);
3122     /*
3123     sigc::connection *connection = new sigc::connection(
3124         desktop->connectSetStyle(
3125             sigc::bind(sigc::ptr_fun(sp_style_changed),
3126                        desktop)) );
3128     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection),
3129                      connection); */
3131     return tbl;
3135 //########################
3136 //##    Text Toolbox    ##
3137 //########################
3138 /*
3139 static void
3140 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3142     //Call back for letter sizing spinbutton
3145 static void
3146 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3148     //Call back for line height spinbutton
3151 static void
3152 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3154     //Call back for horizontal kerning spinbutton
3157 static void
3158 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3160     //Call back for vertical kerning spinbutton
3163 static void
3164 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3166     //Call back for letter rotation spinbutton
3167 }*/
3169 namespace {
3171 bool visible = false;
3173 void
3174 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
3177     SPStyle *query =
3178         sp_style_new ();
3180     int result_family =
3181         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3183     int result_style =
3184         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3186     int result_numbers =
3187         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3189     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3191     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3192     if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3193     {
3194         Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3196         if (repr)
3197         {
3198             sp_style_read_from_repr (query, repr);
3199         }
3200         else
3201         {
3202             return;
3203         }
3204     }
3206     if (query->text)
3207     {
3208         if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3209             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3210             gtk_entry_set_text (GTK_ENTRY (entry), "");
3212         } else if (query->text->font_family.value) {
3214             GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3215             gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3217             Gtk::TreePath path;
3218             try {
3219                 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3220             } catch (...) {
3221                 return;
3222             }
3224             GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3225             GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3227             g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3229             gtk_tree_selection_select_path (tselection, path.gobj());
3230             gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3232             g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3233         }
3235         //Size
3236         GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3237         char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3238         g_object_set_data (tbl, "size-block", gpointer(1));
3239         gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3240         g_object_set_data (tbl, "size-block", gpointer(0));
3241         free (str);
3243         //Anchor
3244         if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3245         {
3246             GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3247             g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3248             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3249             g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3250         }
3251         else
3252         {
3253             if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3254             {
3255                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3256                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3257                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3258                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3259             }
3260             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3261             {
3262                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3263                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3264                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3265                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3266             }
3267             else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3268             {
3269                 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3270                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3271                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3272                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3273             }
3274         }
3276         //Style
3277         {
3278             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3280             gboolean active = gtk_toggle_button_get_active (button);
3281             gboolean check  = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3283             if (active != check)
3284             {
3285                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3286                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3287                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3288             }
3289         }
3291         {
3292             GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3294             gboolean active = gtk_toggle_button_get_active (button);
3295             gboolean check  = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3297             if (active != check)
3298             {
3299                 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3300                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3301                 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3302             }
3303         }
3305         //Orientation
3306         //locking both buttons, changing one affect all group (both)
3307         GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3308         g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3310         GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3311         g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3313         if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3314         {
3315             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3316         }
3317         else
3318         {
3319             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3320         }
3321         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3322         g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3323     }
3326 void
3327 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
3329     sp_text_toolbox_selection_changed (selection, tbl);
3332 void
3333 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3335     sp_text_toolbox_selection_changed (NULL, tbl);
3338 void
3339 sp_text_toolbox_family_changed (GtkTreeSelection    *selection,
3340                                 GObject             *tbl)
3342     SPDesktop    *desktop = SP_ACTIVE_DESKTOP;
3343     GtkTreeModel *model = 0;
3344     GtkWidget    *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3345     GtkWidget    *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3346     GtkTreeIter   iter;
3347     char         *family = 0;
3349     gdk_pointer_ungrab (GDK_CURRENT_TIME);
3350     gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3352     if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3353         return;
3354     }
3356     gtk_tree_model_get (model, &iter, 0, &family, -1);
3358     if (g_object_get_data (G_OBJECT (selection), "block"))
3359     {
3360         gtk_entry_set_text (GTK_ENTRY (entry), family);
3361         return;
3362     }
3364     gtk_widget_hide (popdown);
3365     visible = false;
3367     gtk_entry_set_text (GTK_ENTRY (entry), family);
3369     SPStyle *query =
3370         sp_style_new ();
3372     int result_numbers =
3373         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3375     SPCSSAttr *css = sp_repr_css_attr_new ();
3376     sp_repr_css_set_property (css, "font-family", family);
3378     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3379     if (result_numbers == QUERY_STYLE_NOTHING)
3380     {
3381         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3382         sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3383     }
3384     else
3385     {
3386         sp_desktop_set_style (desktop, css, true, true);
3387     }
3389     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3390                                    _("Text: Change font family"));
3391     sp_repr_css_attr_unref (css);
3392     free (family);
3393     gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3395     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3398 void
3399 sp_text_toolbox_family_entry_activate (GtkEntry     *entry,
3400                                        GObject      *tbl)
3402     const char *family = gtk_entry_get_text (entry);
3404     try {
3405         Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3406         GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3407         GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3408         gtk_tree_selection_select_path (selection, path.gobj());
3409         gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3410         gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3411     } catch (...) {
3412         if (family && strlen (family))
3413         {
3414             gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3415         }
3416     }
3419 void
3420 sp_text_toolbox_anchoring_toggled (GtkRadioButton   *button,
3421                                    gpointer          data)
3423     if (g_object_get_data (G_OBJECT (button), "block")) return;
3424     if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3425     int prop = GPOINTER_TO_INT(data);
3427     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3428     SPCSSAttr *css = sp_repr_css_attr_new ();
3430     switch (prop)
3431     {
3432         case 0:
3433         {
3434             sp_repr_css_set_property (css, "text-anchor", "start");
3435             sp_repr_css_set_property (css, "text-align", "start");
3436             break;
3437         }
3438         case 1:
3439         {
3440             sp_repr_css_set_property (css, "text-anchor", "middle");
3441             sp_repr_css_set_property (css, "text-align", "center");
3442             break;
3443         }
3445         case 2:
3446         {
3447             sp_repr_css_set_property (css, "text-anchor", "end");
3448             sp_repr_css_set_property (css, "text-align", "end");
3449             break;
3450         }
3452         case 3:
3453         {
3454             sp_repr_css_set_property (css, "text-anchor", "start");
3455             sp_repr_css_set_property (css, "text-align", "justify");
3456             break;
3457         }
3458     }
3460     SPStyle *query =
3461         sp_style_new ();
3462     int result_numbers =
3463         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3465     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3466     if (result_numbers == QUERY_STYLE_NOTHING)
3467     {
3468         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3469     }
3471     sp_desktop_set_style (desktop, css, true, true);
3472     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3473                                    _("Text: Change alignment"));
3474     sp_repr_css_attr_unref (css);
3476     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3479 void
3480 sp_text_toolbox_style_toggled (GtkToggleButton  *button,
3481                                gpointer          data)
3483     if (g_object_get_data (G_OBJECT (button), "block")) return;
3485     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3486     SPCSSAttr   *css        = sp_repr_css_attr_new ();
3487     int          prop       = GPOINTER_TO_INT(data);
3488     bool         active     = gtk_toggle_button_get_active (button);
3491     switch (prop)
3492     {
3493         case 0:
3494         {
3495             sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
3496             break;
3497         }
3499         case 1:
3500         {
3501             sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
3502             break;
3503         }
3504     }
3506     SPStyle *query =
3507         sp_style_new ();
3508     int result_numbers =
3509         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3511     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3512     if (result_numbers == QUERY_STYLE_NOTHING)
3513     {
3514         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3515     }
3517     sp_desktop_set_style (desktop, css, true, true);
3518     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3519                                    _("Text: Change font style"));
3520     sp_repr_css_attr_unref (css);
3522     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3525 void
3526 sp_text_toolbox_orientation_toggled (GtkRadioButton  *button,
3527                                      gpointer         data)
3529     if (g_object_get_data (G_OBJECT (button), "block")) {
3530         g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3531         return;
3532     }
3534     SPDesktop   *desktop    = SP_ACTIVE_DESKTOP;
3535     SPCSSAttr   *css        = sp_repr_css_attr_new ();
3536     int          prop       = GPOINTER_TO_INT(data);
3538     switch (prop)
3539     {
3540         case 0:
3541         {
3542             sp_repr_css_set_property (css, "writing-mode", "lr");
3543             break;
3544         }
3546         case 1:
3547         {
3548             sp_repr_css_set_property (css, "writing-mode", "tb");
3549             break;
3550         }
3551     }
3553     SPStyle *query =
3554         sp_style_new ();
3555     int result_numbers =
3556         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3558     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3559     if (result_numbers == QUERY_STYLE_NOTHING)
3560     {
3561         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3562     }
3564     sp_desktop_set_style (desktop, css, true, true);
3565     sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3566                                    _("Text: Change orientation"));
3567     sp_repr_css_attr_unref (css);
3569     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3572 gboolean
3573 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3575     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3576     if (!desktop) return FALSE;
3578     switch (get_group0_keyval (event)) {
3579         case GDK_Escape: // defocus
3580             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3581             return TRUE; // I consumed the event
3582             break;
3583         case GDK_Return: // defocus
3584         case GDK_KP_Enter:
3585             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3586             return TRUE; // I consumed the event
3587             break;
3588     }
3589     return FALSE;
3592 gboolean
3593 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3595     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3596     if (!desktop) return FALSE;
3598     switch (get_group0_keyval (event)) {
3599         case GDK_Escape: // defocus
3600             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3601             sp_text_toolbox_selection_changed (NULL, tbl); // update
3602             return TRUE; // I consumed the event
3603             break;
3604     }
3605     return FALSE;
3608 gboolean
3609 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3611     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3612     if (!desktop) return FALSE;
3614     switch (get_group0_keyval (event)) {
3615         case GDK_Escape: // defocus
3616             gtk_widget_hide (w);
3617             visible = false;
3618             gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3619             return TRUE; // I consumed the event
3620             break;
3621     }
3622     return FALSE;
3626 void
3627 sp_text_toolbox_size_changed  (GtkComboBox *cbox,
3628                                GObject     *tbl)
3630     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3632     if (g_object_get_data (tbl, "size-block")) return;
3634 #if GTK_CHECK_VERSION(2,6,0)
3635     char *text = gtk_combo_box_get_active_text (cbox);
3636 #else // GTK_CHECK_VERSION(2,6,0)
3637     GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3638     GtkTreeIter iter;
3639     char *text = NULL;
3641     if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3642         gtk_tree_model_get (model, &iter, 0, &text, -1);
3643 #endif // GTK_CHECK_VERSION(2,6,0)
3645     SPCSSAttr *css = sp_repr_css_attr_new ();
3646     sp_repr_css_set_property (css, "font-size", text);
3647     free (text);
3649     SPStyle *query =
3650         sp_style_new ();
3651     int result_numbers =
3652         sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3654     // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3655     if (result_numbers == QUERY_STYLE_NOTHING)
3656     {
3657         sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3658     }
3660     sp_desktop_set_style (desktop, css, true, true);
3661     sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
3662                                    _("Text: Change font size"));
3663     sp_repr_css_attr_unref (css);
3666     if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3667         gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3670 void
3671 sp_text_toolbox_text_popdown_clicked    (GtkButton          *button,
3672                                          GObject            *tbl)
3674     GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3675     GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3676     int x, y;
3678     if (!visible)
3679     {
3680         gdk_window_get_origin (widget->window, &x, &y);
3681         gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
3682         gtk_widget_show_all (popdown);
3684         gdk_pointer_grab (widget->window, TRUE,
3685                           GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3686                                         GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3687                                         GDK_POINTER_MOTION_MASK),
3688                           NULL, NULL, GDK_CURRENT_TIME);
3690         gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3692         visible = true;
3693     }
3694     else
3695     {
3696         gdk_pointer_ungrab (GDK_CURRENT_TIME);
3697         gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3698         gtk_widget_hide (popdown);
3699         visible = false;
3700     }
3703 gboolean
3704 sp_text_toolbox_entry_focus_in  (GtkWidget        *entry,
3705                                  GdkEventFocus    *event,
3706                                  GObject          *tbl)
3708     gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3709     return FALSE;
3712 gboolean
3713 sp_text_toolbox_popdown_focus_out (GtkWidget        *popdown,
3714                                    GdkEventFocus    *event,
3715                                    GObject          *tbl)
3717     SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3719     gtk_widget_hide (popdown);
3720     visible = false;
3721     gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3722     return TRUE;
3725 void
3726 cell_data_func  (GtkTreeViewColumn *column,
3727                  GtkCellRenderer   *cell,
3728                  GtkTreeModel      *tree_model,
3729                  GtkTreeIter       *iter,
3730                  gpointer           data)
3732     char        *family,
3733         *family_escaped,
3734         *sample_escaped;
3736     static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3738     gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3740     family_escaped = g_markup_escape_text (family, -1);
3741     sample_escaped = g_markup_escape_text (sample, -1);
3743     std::stringstream markup;
3744     markup << family_escaped << "  <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3745     g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3747     free (family);
3748     free (family_escaped);
3749     free (sample_escaped);
3752 static void delete_completion(GObject *obj, GtkWidget *entry) {
3753     GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3754     if (completion) {
3755         gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3756         g_object_unref (completion);
3757     }
3760 GtkWidget*
3761 sp_text_toolbox_new (SPDesktop *desktop)
3763     GtkWidget   *tbl = gtk_hbox_new (FALSE, 0);
3765     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3766     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3768     GtkTooltips *tt = gtk_tooltips_new();
3769     Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3771     ////////////Family
3772     //Window
3773     GtkWidget   *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3774     gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3776     //Entry
3777     GtkWidget           *entry = gtk_entry_new ();
3778     gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3779     GtkEntryCompletion  *completion = gtk_entry_completion_new ();
3780     gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3781     gtk_entry_completion_set_text_column (completion, 0);
3782     gtk_entry_completion_set_minimum_key_length (completion, 1);
3783     g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3784     gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3785     gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
3786     aux_toolbox_space (tbl, 1);
3787     gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3788     g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
3790     //Button
3791     GtkWidget   *button = gtk_button_new ();
3792     gtk_container_add       (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3793     gtk_box_pack_start      (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3795     //Popdown
3796     GtkWidget           *sw = gtk_scrolled_window_new (NULL, NULL);
3797     GtkWidget           *treeview = gtk_tree_view_new ();
3799     GtkCellRenderer     *cell = gtk_cell_renderer_text_new ();
3800     GtkTreeViewColumn   *column = gtk_tree_view_column_new ();
3801     gtk_tree_view_column_pack_start (column, cell, FALSE);
3802     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3803     gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3804     gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3806     gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3807     gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3808 #if GTK_CHECK_VERSION(2,6,0)
3809     gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3810 #endif // GTK_CHECK_VERSION(2,6,0)
3812     //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3814     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
3815     gtk_container_add (GTK_CONTAINER (sw), treeview);
3817     gtk_container_add (GTK_CONTAINER (window), sw);
3818     gtk_widget_set_size_request (window, 300, 450);
3820     g_signal_connect (G_OBJECT (entry),  "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3821     g_signal_connect (G_OBJECT (entry),  "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3822     g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3824     g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3826     g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3827     g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3829     GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3830     g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3832     g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3833     g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3834     g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3835     g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3836     g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3838     GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3839     aux_toolbox_space (tbl, 1);
3840     GtkWidget *box = gtk_event_box_new ();
3841     gtk_container_add (GTK_CONTAINER (box), image);
3842     gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3843     g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3844     GtkTooltips *tooltips = gtk_tooltips_new ();
3845     gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3846     gtk_widget_hide (GTK_WIDGET (box));
3847     g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3849     ////////////Size
3850     const char *sizes[] = {
3851         "4", "6", "8", "9", "10", "11", "12", "13", "14",
3852         "16", "18", "20", "22", "24", "28",
3853         "32", "36", "40", "48", "56", "64", "72", "144"
3854     };
3856     GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3857     for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3858     gtk_widget_set_size_request (cbox, 80, -1);
3859     aux_toolbox_space (tbl, 1);
3860     gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3861     g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3862     g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3863     gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3865     //spacer
3866     aux_toolbox_space (tbl, 4);
3867     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3869     ////////////Text anchor
3870     GtkWidget *group   = gtk_radio_button_new (NULL);
3871     GtkWidget *row     = gtk_hbox_new (FALSE, 4);
3872     g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3874     // left
3875     GtkWidget *rbutton = group;
3876     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3877     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3878     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3880     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3881     g_object_set_data   (G_OBJECT (tbl), "text-start", rbutton);
3882     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3883     gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3885     // center
3886     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3887     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3888     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3889     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3891     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3892     g_object_set_data   (G_OBJECT (tbl), "text-middle", rbutton);
3893     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
3894     gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3896     // right
3897     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3898     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3899     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3900     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3902     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3903     g_object_set_data   (G_OBJECT (tbl), "text-end", rbutton);
3904     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3905     gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3907     // fill
3908     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3909     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3910     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3911     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3913     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3914     g_object_set_data   (G_OBJECT (tbl), "text-fill", rbutton);
3915     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3916     gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3918     aux_toolbox_space (tbl, 1);
3919     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3921     //spacer
3922     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3924     ////////////Text style
3925     row = gtk_hbox_new (FALSE, 4);
3927     // bold
3928     rbutton = gtk_toggle_button_new ();
3929     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3930     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3931     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3932     gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3934     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3935     g_object_set_data   (G_OBJECT (tbl), "style-bold", rbutton);
3936     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3938     // italic
3939     rbutton = gtk_toggle_button_new ();
3940     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3941     gtk_container_add           (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3942     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3943     gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3945     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3946     g_object_set_data   (G_OBJECT (tbl), "style-italic", rbutton);
3947     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
3949     aux_toolbox_space (tbl, 1);
3950     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3952     //spacer
3953     gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3955     ////////////Text orientation
3956     group   = gtk_radio_button_new (NULL);
3957     row     = gtk_hbox_new (FALSE, 4);
3958     g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3960     // horizontal
3961     rbutton = group;
3962     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3963     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
3964     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3965     gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3967     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3968     g_object_set_data   (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3969     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3971     // vertical
3972     rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3973     gtk_button_set_relief       (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3974     gtk_container_add           (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
3975     gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3976     gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3978     gtk_box_pack_start  (GTK_BOX  (row), rbutton, FALSE, FALSE, 0);
3979     g_object_set_data   (G_OBJECT (tbl), "orientation-vertical", rbutton);
3980     g_signal_connect    (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
3981     gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3984     //watch selection
3985     Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3987     sigc::connection *c_selection_changed =
3988         new sigc::connection (sp_desktop_selection (desktop)->connectChanged
3989                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3990     pool->add_connection ("selection-changed", c_selection_changed);
3992     sigc::connection *c_selection_modified =
3993         new sigc::connection (sp_desktop_selection (desktop)->connectModified
3994                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3995     pool->add_connection ("selection-modified", c_selection_modified);
3997     sigc::connection *c_subselection_changed =
3998         new sigc::connection (desktop->connectToolSubselectionChanged
3999                               (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4000     pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4002     Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4005 #if 0
4006     // horizontal
4007     {
4008         GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
4009         GtkWidget *b = group = gtk_radio_button_new (NULL);
4010         gtk_container_add (GTK_CONTAINER (b), px);
4011         gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
4012         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4013         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4014         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4015     }
4017     // vertical
4018     {
4019         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
4020         GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4021         gtk_container_add (GTK_CONTAINER (b), px);
4022         gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
4023         gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4024         gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4025         gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4026     }
4028     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4030     // letter spacing
4031     {
4032         {
4033             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
4034             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4035             gtk_container_add (GTK_CONTAINER (hb), image);
4036             gtk_widget_show(image);
4037             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4038         }
4040         {
4041             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
4042                                              "tools.text", "letter_spacing", 0.0,
4043                                              us, tbl, FALSE, NULL,
4044                                              -1000.0, 1000.0, 0.1, 0.1,
4045                                              sp_text_letter_changed, 0.1, 1);
4046             gtk_widget_set_size_request (hb, 45, 6);
4047             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4048         }
4049     }
4051     // line spacing
4052     {
4053         {
4054             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
4055             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4056             gtk_container_add (GTK_CONTAINER (hb), image);
4057             gtk_widget_show(image);
4058             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4059         }
4061         {
4062             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
4063                                              "tools.text", "line_spacing", 0,
4064                                              us, tbl, FALSE, NULL,
4065                                              -1000.0, 1000.0, 0.1, 0.1,
4066                                              sp_text_line_changed, 0.1, 1);
4067             gtk_widget_set_size_request (hb, 45, 0);
4068             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
4069         }
4070     }
4072     {
4073         // horizontal kerning/vertical kerning units menu: create
4074         GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
4075         sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
4076         sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
4078         aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4080         // horizontal kerning
4081         {
4082             {
4083                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
4084                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4085                 gtk_container_add (GTK_CONTAINER (hb), image);
4086                 gtk_widget_show(image);
4087                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4088             }
4090             {
4091                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
4092                                                  "tools.text", "horizontal_kerning", 0,
4093                                                  us, tbl, FALSE, NULL,
4094                                                  -100.00, 100.00, 0.01, 0.1,
4095                                                  sp_text_horiz_kern_changed);
4096                 gtk_widget_set_size_request (hb, 45, 0);
4097                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4098             }
4099         }
4101         // vertical kerning
4102         {
4103             {
4104                 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
4105                 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4106                 gtk_container_add (GTK_CONTAINER (hb), image);
4107                 gtk_widget_show(image);
4108                 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4109             }
4111             {
4112                 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
4113                                                  "tools.text", "vertical_kerning", 0,
4114                                                  us, tbl, FALSE, NULL,
4115                                                  -100.00, 100.00, 0.01, 0.1,
4116                                                  sp_text_vert_kern_changed);
4117                 gtk_widget_set_size_request (hb, 45, 0);
4118                 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
4119             }
4120         }
4122         // add the units menu
4123         gtk_widget_show(us);
4124         gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
4125         gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
4126     }
4128     // letter rotation
4129     aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4130     {
4131         {
4132             GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
4133             GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4134             gtk_container_add (GTK_CONTAINER (hb), image);
4135             gtk_widget_show(image);
4136             gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4137         }
4138         {
4139             GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
4140                                              "tools.text", "letter_rotation", 0,
4141                                              us, tbl, FALSE, NULL,
4142                                              -180.0, 180.0, 0.1, 0.1,
4143                                              sp_text_letter_rotation_changed, 0.1, 1);
4144             gtk_widget_set_size_request (hb, 45, 0);
4145             gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4146         }
4147         // rotation degree label
4148         {
4149             GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4150             gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4151         }
4152     }
4154     // Remove Manual Kerns
4155     {
4156         GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4157         GtkWidget *button = gtk_button_new ();
4158         gtk_container_add (GTK_CONTAINER (button), px);
4159         gtk_widget_show(button);
4160         gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4161         gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4162         gtk_widget_set_sensitive(button, TRUE);
4163         gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4164     }
4165 #endif
4167     gtk_widget_show_all (tbl);
4168     return tbl;
4170 } // end of sp_text_toolbox_new()
4172 }//<unnamed> namespace
4175 //#########################
4176 //##  Connector Toolbox  ##
4177 //#########################
4179 static void sp_connector_path_set_avoid(void)
4181     cc_selection_set_avoid(true);
4185 static void sp_connector_path_set_ignore(void)
4187     cc_selection_set_avoid(false);
4192 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
4194     // quit if run by the _changed callbacks
4195     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4196         return;
4197     }
4199     SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
4200             "desktop");
4201     SPDocument *doc = sp_desktop_document(desktop);
4203     if (!sp_document_get_undo_sensitive(doc))
4204     {
4205         return;
4206     }
4208     // in turn, prevent callbacks from responding
4209     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
4211     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4213     sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4214     SP_OBJECT(desktop->namedview)->updateRepr();
4216     GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4217     for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4218         SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4219         NR::Matrix m = NR::identity();
4220         avoid_item_move(&m, item);
4221     }
4223     if (items) {
4224         g_slist_free(items);
4225     }
4227     sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4228             _("Change connector spacing"));
4230     g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
4232     spinbutton_defocus(GTK_OBJECT(tbl));
4235 static void sp_connector_graph_layout(void)
4237     if (!SP_ACTIVE_DESKTOP) return;
4239     // hack for clones, see comment in align-and-distribute.cpp
4240     int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4241     prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4243     graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4245     prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4247     sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4250 static void
4251 sp_directed_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4253     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4254         prefs_set_string_attribute("tools.connector", "directedlayout",
4255                 "true");
4256     } else {
4257         prefs_set_string_attribute("tools.connector", "directedlayout",
4258                 "false");
4259     }
4261 static void
4262 sp_nooverlaps_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4264     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4265         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4266                 "true");
4267     } else {
4268         prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4269                 "false");
4270     }
4274 static void connector_length_changed(GtkAdjustment *adj, GtkWidget *tbl)
4276     prefs_set_double_attribute("tools.connector", "length", adj->value);
4277     spinbutton_defocus(GTK_OBJECT(tbl));
4280 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4281         gchar const *name, gchar const *old_value, gchar const *new_value,
4282         bool is_interactive, gpointer data)
4284     GtkWidget *tbl = GTK_WIDGET(data);
4286     if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4287         return;
4288     }
4289     if (strcmp(name, "inkscape:connector-spacing") != 0) {
4290         return;
4291     }
4293     GtkAdjustment *adj = (GtkAdjustment*)
4294             gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4295     gdouble spacing = defaultConnSpacing;
4296     sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4298     gtk_adjustment_set_value(adj, spacing);
4302 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4303     NULL, /* child_added */
4304     NULL, /* child_removed */
4305     connector_tb_event_attr_changed,
4306     NULL, /* content_changed */
4307     NULL  /* order_changed */
4308 };
4311 static GtkWidget *
4312 sp_connector_toolbox_new(SPDesktop *desktop)
4314     GtkTooltips *tt = gtk_tooltips_new();
4315     GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
4317     gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4318     gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4320     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4321             AUX_BETWEEN_BUTTON_GROUPS);
4323     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4324             "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
4325             tt, _("Make connectors avoid selected objects"));
4327     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4328             "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
4329             tt, _("Make connectors ignore selected objects"));
4331     //  interval
4332     gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4333             AUX_BETWEEN_BUTTON_GROUPS);
4335     // Spacing spinbox
4336     {
4337         GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
4338                 _("The amount of space left around objects by auto-routing connectors"),
4339                 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
4340                 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
4341                 connector_spacing_changed, 1, 0);
4343         gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
4344                 AUX_SPACING);
4345     }
4346     // Graph (connector network) layout
4347     sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4348             "graph_layout", GTK_SIGNAL_FUNC(sp_connector_graph_layout),
4349             tt, _("Nicely arrange selected connector network"));
4350     // Default connector length spinbox
4351     {
4352         GtkWidget *connector_length = sp_tb_spinbutton(_("Length:"),
4353                 _("Ideal length for connectors when layout is applied"),
4354                 "tools.connector", "length", 100, NULL, tbl, TRUE,
4355                 "inkscape:connector-length", 10, 1000, 10.0, 100.0,
4356                 connector_length_changed, 1, 0);
4358         gtk_box_pack_start(GTK_BOX(tbl), connector_length, FALSE, FALSE,
4359                 AUX_SPACING);
4360     }
4361     gchar const *tbuttonstate;
4362     // Directed edges toggle button
4363     {
4364         GtkWidget *tbutton = gtk_toggle_button_new ();
4365         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4366         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "directed_graph"));
4367         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4368         gtk_tooltips_set_tip(tt, tbutton, _("Make connectors with end-markers (arrows) point downwards"), NULL);
4370         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4371         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_directed_graph_layout_toggled), tbl);
4372         tbuttonstate = prefs_get_string_attribute("tools.connector", "directedlayout");
4373         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4374                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4375     }
4376     // Avoid overlaps toggle button
4377     {
4378         GtkWidget *tbutton = gtk_toggle_button_new ();
4379         gtk_button_set_relief       (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4380         gtk_container_add           (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "remove_overlaps"));
4381         gtk_toggle_button_set_mode  (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4382         gtk_tooltips_set_tip(tt, tbutton, _("Do not allow overlapping shapes"), NULL);
4384         gtk_box_pack_start  (GTK_BOX  (tbl), tbutton, FALSE, FALSE, 0);
4385         g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_nooverlaps_graph_layout_toggled), tbl);
4386         tbuttonstate = prefs_get_string_attribute("tools.connector", "avoidoverlaplayout");
4387         gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4388                 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4389     }
4391     gtk_widget_show_all(tbl);
4392     sp_set_font_size_smaller (tbl);
4394     // Code to watch for changes to the connector-spacing attribute in
4395     // the XML.
4396     Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4397     g_assert(repr != NULL);
4399     Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
4400             gtk_object_get_data(GTK_OBJECT(tbl), "repr");
4402     if (oldrepr) { // remove old listener
4403         sp_repr_remove_listener_by_data(oldrepr, tbl);
4404         Inkscape::GC::release(oldrepr);
4405         oldrepr = NULL;
4406         g_object_set_data(G_OBJECT(tbl), "repr", NULL);
4407     }
4409     if (repr) {
4410         g_object_set_data(G_OBJECT(tbl), "repr", repr);
4411         Inkscape::GC::anchor(repr);
4412         sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
4413         sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
4414     }
4416     return tbl;
4418 } // end of sp_connector_toolbox_new()
4420 static void paintbucket_channels_changed(EgeSelectOneAction* act, GtkWidget* tbl)
4422     gint channels = ege_select_one_action_get_active( act );
4423     flood_channels_set_channels( channels );
4426 static void paintbucket_threshold_changed(GtkAdjustment *adj, GtkWidget *tbl)
4428     prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4431 static void paintbucket_offset_changed(GtkAdjustment *adj, GtkWidget *tbl)
4433     UnitTracker* tracker = reinterpret_cast<UnitTracker*>(gtk_object_get_data(GTK_OBJECT(tbl), "tracker"));
4434     SPUnit const *unit = tracker->getActiveUnit();
4437     prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
4438     spinbutton_defocus(GTK_OBJECT(tbl));
4441 static GtkWidget *
4442 sp_paintbucket_toolbox_new(SPDesktop *desktop)
4444     GtkWidget *holder = gtk_hbox_new(FALSE, 0);
4445     gtk_object_set_data(GTK_OBJECT(holder), "dtw", desktop->canvas);
4446     gtk_object_set_data(GTK_OBJECT(holder), "desktop", desktop);
4448     gchar const * descr =
4449         "<ui>"
4450         "  <toolbar name='PaintbucketToolbar'>"
4451         "    <toolitem action='ChannelsAction' />"
4452         "    <separator />"
4453         "    <toolitem action='ThresholdAction' />"
4454         "    <separator />"
4455         "    <toolitem action='OffsetAction' />"
4456         "  </toolbar>"
4457         "</ui>";
4458     GtkActionGroup* mainActions = gtk_action_group_new("main");
4460     EgeAdjustmentAction* eact = 0;
4462     {
4463         GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4465         GList* items = 0;
4466         gint count = 0;
4467         for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
4468         {
4469             GtkTreeIter iter;
4470             gtk_list_store_append( model, &iter );
4471             gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4472             count++;
4473         }
4474         g_list_free( items );
4475         items = 0;
4476         EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by:"), _(""), NULL, GTK_TREE_MODEL(model) );
4477         ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
4478         g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
4479         gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
4480     }
4482     // Spacing spinbox
4483     {
4484         eact = create_adjustment_action(
4485             "ThresholdAction",
4486             _("Threshold:"),
4487             _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
4488             "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
4489             "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
4490             0, 0, 0,
4491             paintbucket_threshold_changed, 1, 0 );
4493         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4494     }
4496     // Create the units menu.
4497     UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
4498     tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
4499     gtk_object_set_data( GTK_OBJECT(holder), "tracker", tracker );
4500     {
4501         GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), _("") );
4502         gtk_action_group_add_action( mainActions, act );
4503     }
4505     // Offset spinbox
4506     {
4507         eact = create_adjustment_action(
4508             "OffsetAction",
4509             _("Grow/shrink by:"),
4510             _("The amount to grow (positive) or shrink (negative) the created fill path"),
4511             "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
4512             "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
4513             0, 0, 0,
4514             paintbucket_offset_changed, 1, 2);
4515         tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
4517         gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4518     }
4521     GtkUIManager* mgr = gtk_ui_manager_new();
4522     GError* errVal = 0;
4524     gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
4525     gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
4527     GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/PaintbucketToolbar" );
4528     gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
4529     gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), GTK_ICON_SIZE_SMALL_TOOLBAR );
4531     gtk_box_pack_start( GTK_BOX(holder), toolBar, TRUE, TRUE, 0 );
4534     Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch(NULL, _("Style of Paint Bucket fill objects"));
4535     swatch->setDesktop (desktop);
4536     swatch->setClickVerb (SP_VERB_CONTEXT_PAINTBUCKET_PREFS);
4537     swatch->setWatchedTool ("tools.paintbucket", true);
4538     GtkWidget *swatch_ = GTK_WIDGET(swatch->gobj());
4539     gtk_box_pack_end( GTK_BOX(holder), swatch_, FALSE, FALSE, 0 );
4541     gtk_widget_show_all( holder );
4542     sp_set_font_size_smaller( holder );
4544     return holder;
4547 /*
4548   Local Variables:
4549   mode:c++
4550   c-file-style:"stroustrup"
4551   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4552   indent-tabs-mode:nil
4553   fill-column:99
4554   End:
4555 */
4556 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :