1 /** \file
2 * Controls bars for some of Inkscape's tools
3 * (for some tools, they are in their own files)
4 */
6 /*
7 *
8 * Authors:
9 * MenTaLguY <mental@rydia.net>
10 * Lauris Kaplinski <lauris@kaplinski.com>
11 * bulia byak <buliabyak@users.sf.net>
12 * Frank Felfe <innerspace@iname.com>
13 * John Cliff <simarilius@yahoo.com>
14 * David Turner <novalis@gnu.org>
15 * Josh Andler <scislac@scislac.com>
16 * Jon A. Cruz <jon@joncruz.org>
17 *
18 * Copyright (C) 2004 David Turner
19 * Copyright (C) 2003 MenTaLguY
20 * Copyright (C) 1999-2006 authors
21 * Copyright (C) 2001-2002 Ximian, Inc.
22 *
23 * Released under GNU GPL, read the file 'COPYING' for more information
24 */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <cstring>
31 #include <string>
33 #include <gtkmm.h>
34 #include <gtk/gtk.h>
35 #include <iostream>
36 #include <sstream>
38 #include "widgets/button.h"
39 #include "widgets/widget-sizes.h"
40 #include "widgets/spw-utilities.h"
41 #include "widgets/spinbutton-events.h"
42 #include "dialogs/text-edit.h"
43 #include "dialogs/dialog-events.h"
45 #include "ui/widget/style-swatch.h"
47 #include "prefs-utils.h"
48 #include "verbs.h"
49 #include "sp-namedview.h"
50 #include "desktop.h"
51 #include "desktop-handles.h"
52 #include "xml/repr.h"
53 #include "xml/node-event-vector.h"
54 #include "xml/attribute-record.h"
55 #include <glibmm/i18n.h>
56 #include "helper/unit-menu.h"
57 #include "helper/units.h"
58 #include "live_effects/effect.h"
60 #include "inkscape.h"
61 #include "conn-avoid-ref.h"
64 #include "select-toolbar.h"
65 #include "gradient-toolbar.h"
67 #include "connector-context.h"
68 #include "node-context.h"
69 #include "draw-context.h"
70 #include "shape-editor.h"
71 #include "tweak-context.h"
72 #include "sp-rect.h"
73 #include "box3d.h"
74 #include "box3d-context.h"
75 #include "sp-star.h"
76 #include "sp-spiral.h"
77 #include "sp-ellipse.h"
78 #include "sp-text.h"
79 #include "sp-flowtext.h"
80 #include "sp-clippath.h"
81 #include "sp-mask.h"
82 #include "style.h"
83 #include "selection.h"
84 #include "selection-chemistry.h"
85 #include "document-private.h"
86 #include "desktop-style.h"
87 #include "../libnrtype/font-lister.h"
88 #include "../libnrtype/font-instance.h"
89 #include "../connection-pool.h"
90 #include "../prefs-utils.h"
91 #include "../inkscape-stock.h"
92 #include "icon.h"
93 #include "graphlayout/graphlayout.h"
94 #include "interface.h"
95 #include "shortcuts.h"
97 #include "mod360.h"
99 #include "toolbox.h"
101 #include "flood-context.h"
103 #include "ink-action.h"
104 #include "ege-adjustment-action.h"
105 #include "ege-output-action.h"
106 #include "ege-select-one-action.h"
107 #include "helper/unit-tracker.h"
109 #include "svg/css-ostringstream.h"
111 #include "widgets/calligraphic-profile-rename.h"
113 using Inkscape::UnitTracker;
115 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
116 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
118 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
120 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
121 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
122 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
123 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
124 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
125 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
126 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
127 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
128 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
129 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
130 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
131 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
132 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
133 static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
135 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
138 Inkscape::IconSize prefToSize( gchar const *path, gchar const *attr, int base ) {
139 static Inkscape::IconSize sizeChoices[] = {
140 Inkscape::ICON_SIZE_LARGE_TOOLBAR,
141 Inkscape::ICON_SIZE_SMALL_TOOLBAR,
142 Inkscape::ICON_SIZE_MENU
143 };
144 int index = prefs_get_int_attribute_limited( path, attr, base, 0, G_N_ELEMENTS(sizeChoices) );
145 return sizeChoices[index];
146 }
148 static struct {
149 gchar const *type_name;
150 gchar const *data_name;
151 sp_verb_t verb;
152 sp_verb_t doubleclick_verb;
153 } const tools[] = {
154 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
155 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
156 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
157 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
158 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
159 { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
160 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
161 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
162 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
163 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
164 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
165 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
166 { "SPEraserContext", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS },
167 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
168 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
169 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
170 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
171 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
172 { NULL, NULL, 0, 0 }
173 };
175 static struct {
176 gchar const *type_name;
177 gchar const *data_name;
178 GtkWidget *(*create_func)(SPDesktop *desktop);
179 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
180 gchar const *ui_name;
181 gint swatch_verb_id;
182 gchar const *swatch_tool;
183 gchar const *swatch_tip;
184 } const aux_toolboxes[] = {
185 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
186 SP_VERB_INVALID, 0, 0},
187 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
188 SP_VERB_INVALID, 0, 0},
189 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
190 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", N_("Color/opacity used for color tweaking")},
191 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
192 SP_VERB_INVALID, 0, 0},
193 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
194 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", N_("Style of new stars")},
195 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
196 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", N_("Style of new rectangles")},
197 { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar",
198 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", N_("Style of new 3D boxes")},
199 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
200 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", N_("Style of new ellipses")},
201 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
202 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", N_("Style of new spirals")},
203 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
204 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", N_("Style of new paths created by Pencil")},
205 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
206 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", N_("Style of new paths created by Pen")},
207 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
208 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", N_("Style of new calligraphic strokes")},
209 { "SPEraserContext", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar",
210 SP_VERB_CONTEXT_ERASER_PREFS, "tools.eraser", _("TBD")},
211 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
212 SP_VERB_INVALID, 0, 0},
213 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
214 SP_VERB_INVALID, 0, 0},
215 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
216 SP_VERB_INVALID, 0, 0},
217 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
218 SP_VERB_INVALID, 0, 0},
219 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
220 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", N_("Style of Paint Bucket fill objects")},
221 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
222 };
224 #define TOOLBAR_SLIDER_HINT "full"
226 static gchar const * ui_descr =
227 "<ui>"
228 " <toolbar name='SelectToolbar'>"
229 " <toolitem action='EditSelectAll' />"
230 " <toolitem action='EditSelectAllInAllLayers' />"
231 " <toolitem action='EditDeselect' />"
232 " <separator />"
233 " <toolitem action='ObjectRotate90CCW' />"
234 " <toolitem action='ObjectRotate90' />"
235 " <toolitem action='ObjectFlipHorizontally' />"
236 " <toolitem action='ObjectFlipVertically' />"
237 " <separator />"
238 " <toolitem action='SelectionToBack' />"
239 " <toolitem action='SelectionLower' />"
240 " <toolitem action='SelectionRaise' />"
241 " <toolitem action='SelectionToFront' />"
242 " <separator />"
243 " <toolitem action='XAction' />"
244 " <toolitem action='YAction' />"
245 " <toolitem action='WidthAction' />"
246 " <toolitem action='LockAction' />"
247 " <toolitem action='HeightAction' />"
248 " <toolitem action='UnitsAction' />"
249 " <separator />"
250 " <toolitem action='transform_affect_label' />"
251 " <toolitem action='transform_stroke' />"
252 " <toolitem action='transform_corners' />"
253 " <toolitem action='transform_gradient' />"
254 " <toolitem action='transform_pattern' />"
255 " </toolbar>"
257 " <toolbar name='NodeToolbar'>"
258 " <toolitem action='NodeInsertAction' />"
259 " <toolitem action='NodeDeleteAction' />"
260 " <separator />"
261 " <toolitem action='NodeJoinAction' />"
262 " <toolitem action='NodeBreakAction' />"
263 " <separator />"
264 " <toolitem action='NodeJoinSegmentAction' />"
265 " <toolitem action='NodeDeleteSegmentAction' />"
266 " <separator />"
267 " <toolitem action='NodeCuspAction' />"
268 " <toolitem action='NodeSmoothAction' />"
269 " <toolitem action='NodeSymmetricAction' />"
270 " <separator />"
271 " <toolitem action='NodeLineAction' />"
272 " <toolitem action='NodeCurveAction' />"
273 " <separator />"
274 " <toolitem action='ObjectToPath' />"
275 " <toolitem action='StrokeToPath' />"
276 " <separator />"
277 " <toolitem action='NodeXAction' />"
278 " <toolitem action='NodeYAction' />"
279 " <toolitem action='NodeUnitsAction' />"
280 " <separator />"
281 " <toolitem action='ObjectEditClipPathAction' />"
282 " <toolitem action='ObjectEditMaskPathAction' />"
283 " <toolitem action='EditNextLPEParameterAction' />"
284 " <separator />"
285 " <toolitem action='NodesShowHandlesAction' />"
286 " <toolitem action='NodesShowHelperpath' />"
287 " </toolbar>"
289 " <toolbar name='TweakToolbar'>"
290 " <toolitem action='TweakWidthAction' />"
291 " <separator />"
292 " <toolitem action='TweakForceAction' />"
293 " <toolitem action='TweakPressureAction' />"
294 " <separator />"
295 " <toolitem action='TweakModeAction' />"
296 " <separator />"
297 " <toolitem action='TweakFidelityAction' />"
298 " <separator />"
299 " <toolitem action='TweakChannelsLabel' />"
300 " <toolitem action='TweakDoH' />"
301 " <toolitem action='TweakDoS' />"
302 " <toolitem action='TweakDoL' />"
303 " <toolitem action='TweakDoO' />"
304 " </toolbar>"
306 " <toolbar name='ZoomToolbar'>"
307 " <toolitem action='ZoomIn' />"
308 " <toolitem action='ZoomOut' />"
309 " <separator />"
310 " <toolitem action='Zoom1:0' />"
311 " <toolitem action='Zoom1:2' />"
312 " <toolitem action='Zoom2:1' />"
313 " <separator />"
314 " <toolitem action='ZoomSelection' />"
315 " <toolitem action='ZoomDrawing' />"
316 " <toolitem action='ZoomPage' />"
317 " <toolitem action='ZoomPageWidth' />"
318 " <separator />"
319 " <toolitem action='ZoomPrev' />"
320 " <toolitem action='ZoomNext' />"
321 " </toolbar>"
323 " <toolbar name='StarToolbar'>"
324 " <separator />"
325 " <toolitem action='StarStateAction' />"
326 " <separator />"
327 " <toolitem action='FlatAction' />"
328 " <separator />"
329 " <toolitem action='MagnitudeAction' />"
330 " <toolitem action='SpokeAction' />"
331 " <toolitem action='RoundednessAction' />"
332 " <toolitem action='RandomizationAction' />"
333 " <separator />"
334 " <toolitem action='StarResetAction' />"
335 " </toolbar>"
337 " <toolbar name='RectToolbar'>"
338 " <toolitem action='RectStateAction' />"
339 " <toolitem action='RectWidthAction' />"
340 " <toolitem action='RectHeightAction' />"
341 " <toolitem action='RadiusXAction' />"
342 " <toolitem action='RadiusYAction' />"
343 " <toolitem action='RectUnitsAction' />"
344 " <separator />"
345 " <toolitem action='RectResetAction' />"
346 " </toolbar>"
348 " <toolbar name='3DBoxToolbar'>"
349 " <toolitem action='3DBoxAngleXAction' />"
350 " <toolitem action='3DBoxVPXStateAction' />"
351 " <separator />"
352 " <toolitem action='3DBoxAngleYAction' />"
353 " <toolitem action='3DBoxVPYStateAction' />"
354 " <separator />"
355 " <toolitem action='3DBoxAngleZAction' />"
356 " <toolitem action='3DBoxVPZStateAction' />"
357 " </toolbar>"
359 " <toolbar name='SpiralToolbar'>"
360 " <toolitem action='SpiralStateAction' />"
361 " <toolitem action='SpiralRevolutionAction' />"
362 " <toolitem action='SpiralExpansionAction' />"
363 " <toolitem action='SpiralT0Action' />"
364 " <separator />"
365 " <toolitem action='SpiralResetAction' />"
366 " </toolbar>"
368 " <toolbar name='PenToolbar'>"
369 " <toolitem action='FreehandModeActionPenTemp' />"
370 " <toolitem action='FreehandModeActionPen' />"
371 " <separator />"
372 " <toolitem action='SetPenShapeAction'/>"
373 " </toolbar>"
375 " <toolbar name='PencilToolbar'>"
376 " <toolitem action='FreehandModeActionPencilTemp' />"
377 " <toolitem action='FreehandModeActionPencil' />"
378 " <separator />"
379 " <toolitem action='PencilToleranceAction' />"
380 " <separator />"
381 " <toolitem action='PencilResetAction' />"
382 " <separator />"
383 " <toolitem action='SetPencilShapeAction'/>"
384 " </toolbar>"
386 " <toolbar name='CalligraphyToolbar'>"
387 " <separator />"
388 " <toolitem action='SetProfileAction'/>"
389 " <separator />"
390 " <toolitem action='CalligraphyWidthAction' />"
391 " <toolitem action='PressureAction' />"
392 " <toolitem action='TraceAction' />"
393 " <toolitem action='ThinningAction' />"
394 " <separator />"
395 " <toolitem action='AngleAction' />"
396 " <toolitem action='TiltAction' />"
397 " <toolitem action='FixationAction' />"
398 " <separator />"
399 " <toolitem action='CapRoundingAction' />"
400 " <separator />"
401 " <toolitem action='TremorAction' />"
402 " <toolitem action='WiggleAction' />"
403 " <toolitem action='MassAction' />"
404 " <separator />"
405 " </toolbar>"
407 " <toolbar name='ArcToolbar'>"
408 " <toolitem action='ArcStateAction' />"
409 " <separator />"
410 " <toolitem action='ArcStartAction' />"
411 " <toolitem action='ArcEndAction' />"
412 " <separator />"
413 " <toolitem action='ArcOpenAction' />"
414 " <separator />"
415 " <toolitem action='ArcResetAction' />"
416 " <separator />"
417 " </toolbar>"
419 " <toolbar name='PaintbucketToolbar'>"
420 " <toolitem action='ChannelsAction' />"
421 " <separator />"
422 " <toolitem action='ThresholdAction' />"
423 " <separator />"
424 " <toolitem action='OffsetAction' />"
425 " <toolitem action='PaintbucketUnitsAction' />"
426 " <separator />"
427 " <toolitem action='AutoGapAction' />"
428 " <separator />"
429 " <toolitem action='PaintbucketResetAction' />"
430 " </toolbar>"
432 " <toolbar name='EraserToolbar'>"
433 " <toolitem action='EraserWidthAction' />"
434 " <separator />"
435 " <toolitem action='EraserModeAction' />"
436 " </toolbar>"
438 " <toolbar name='DropperToolbar'>"
439 " <toolitem action='DropperOpacityAction' />"
440 " <toolitem action='DropperPickAlphaAction' />"
441 " <toolitem action='DropperSetAlphaAction' />"
442 " </toolbar>"
444 " <toolbar name='ConnectorToolbar'>"
445 " <toolitem action='ConnectorAvoidAction' />"
446 " <toolitem action='ConnectorIgnoreAction' />"
447 " <toolitem action='ConnectorSpacingAction' />"
448 " <toolitem action='ConnectorGraphAction' />"
449 " <toolitem action='ConnectorLengthAction' />"
450 " <toolitem action='ConnectorDirectedAction' />"
451 " <toolitem action='ConnectorOverlapAction' />"
452 " </toolbar>"
454 "</ui>"
455 ;
457 static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop );
459 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
461 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
462 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
464 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
465 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
467 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
468 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
471 GtkWidget * sp_toolbox_button_new_from_verb_with_doubleclick( GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
472 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
473 Inkscape::UI::View::View *view, GtkTooltips *tt);
475 class VerbAction : public Gtk::Action {
476 public:
477 static Glib::RefPtr<VerbAction> create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
479 virtual ~VerbAction();
480 virtual void set_active(bool active = true);
482 protected:
483 virtual Gtk::Widget* create_menu_item_vfunc();
484 virtual Gtk::Widget* create_tool_item_vfunc();
486 virtual void connect_proxy_vfunc(Gtk::Widget* proxy);
487 virtual void disconnect_proxy_vfunc(Gtk::Widget* proxy);
489 virtual void on_activate();
491 private:
492 Inkscape::Verb* verb;
493 Inkscape::Verb* verb2;
494 Inkscape::UI::View::View *view;
495 GtkTooltips *tooltips;
496 bool active;
498 VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
499 };
502 Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips)
503 {
504 Glib::RefPtr<VerbAction> result;
505 SPAction *action = verb->get_action(view);
506 if ( action ) {
507 //SPAction* action2 = verb2 ? verb2->get_action(view) : 0;
508 result = Glib::RefPtr<VerbAction>(new VerbAction(verb, verb2, view, tooltips));
509 }
511 return result;
512 }
514 VerbAction::VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips) :
515 Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(_(verb->get_name())), Glib::ustring(_(verb->get_tip()))),
516 verb(verb),
517 verb2(verb2),
518 view(view),
519 tooltips(tooltips),
520 active(false)
521 {
522 }
524 VerbAction::~VerbAction()
525 {
526 }
528 Gtk::Widget* VerbAction::create_menu_item_vfunc()
529 {
530 // First call in to get the icon rendered if present in SVG
531 Gtk::Widget *widget = sp_icon_get_icon( property_stock_id().get_value().get_string(), Inkscape::ICON_SIZE_MENU );
532 delete widget;
533 widget = 0;
535 Gtk::Widget* widg = Gtk::Action::create_menu_item_vfunc();
536 // g_message("create_menu_item_vfunc() = %p for '%s'", widg, verb->get_id());
537 return widg;
538 }
540 Gtk::Widget* VerbAction::create_tool_item_vfunc()
541 {
542 // Gtk::Widget* widg = Gtk::Action::create_tool_item_vfunc();
543 Inkscape::IconSize toolboxSize = prefToSize("toolbox.tools", "small");
544 GtkWidget* toolbox = 0;
545 GtkWidget *button = sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
546 SP_BUTTON_TYPE_TOGGLE,
547 verb,
548 verb2,
549 view,
550 tooltips );
551 if ( active ) {
552 sp_button_toggle_set_down( SP_BUTTON(button), active);
553 }
554 gtk_widget_show_all( button );
555 Gtk::Widget* wrapped = Glib::wrap(button);
556 Gtk::ToolItem* holder = Gtk::manage(new Gtk::ToolItem());
557 holder->add(*wrapped);
559 // g_message("create_tool_item_vfunc() = %p for '%s'", holder, verb->get_id());
560 return holder;
561 }
563 void VerbAction::connect_proxy_vfunc(Gtk::Widget* proxy)
564 {
565 // g_message("connect_proxy_vfunc(%p) for '%s'", proxy, verb->get_id());
566 Gtk::Action::connect_proxy_vfunc(proxy);
567 }
569 void VerbAction::disconnect_proxy_vfunc(Gtk::Widget* proxy)
570 {
571 // g_message("disconnect_proxy_vfunc(%p) for '%s'", proxy, verb->get_id());
572 Gtk::Action::disconnect_proxy_vfunc(proxy);
573 }
575 void VerbAction::set_active(bool active)
576 {
577 this->active = active;
578 Glib::SListHandle<Gtk::Widget*> proxies = get_proxies();
579 for ( Glib::SListHandle<Gtk::Widget*>::iterator it = proxies.begin(); it != proxies.end(); ++it ) {
580 Gtk::ToolItem* ti = dynamic_cast<Gtk::ToolItem*>(*it);
581 if (ti) {
582 // *should* have one child that is the SPButton
583 Gtk::Widget* child = ti->get_child();
584 if ( child && SP_IS_BUTTON(child->gobj()) ) {
585 SPButton* button = SP_BUTTON(child->gobj());
586 sp_button_toggle_set_down( button, active );
587 }
588 }
589 }
590 }
592 void VerbAction::on_activate()
593 {
594 if ( verb ) {
595 SPAction *action = verb->get_action(view);
596 if ( action ) {
597 sp_action_perform(action, 0);
598 }
599 }
600 }
602 /* Global text entry widgets necessary for update */
603 /* GtkWidget *dropper_rgb_entry,
604 *dropper_opacity_entry ; */
605 // should be made a private member once this is converted to class
607 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
608 connection->disconnect();
609 delete connection;
610 }
612 static void purge_repr_listener( GObject* obj, GObject* tbl )
613 {
614 (void)obj;
615 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
616 if (oldrepr) { // remove old listener
617 sp_repr_remove_listener_by_data(oldrepr, tbl);
618 Inkscape::GC::release(oldrepr);
619 oldrepr = 0;
620 g_object_set_data( tbl, "repr", NULL );
621 }
622 }
624 GtkWidget *
625 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
626 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
627 Inkscape::UI::View::View *view, GtkTooltips *tt)
628 {
629 SPAction *action = verb->get_action(view);
630 if (!action) return NULL;
632 SPAction *doubleclick_action;
633 if (doubleclick_verb)
634 doubleclick_action = doubleclick_verb->get_action(view);
635 else
636 doubleclick_action = NULL;
638 /* fixme: Handle sensitive/unsensitive */
639 /* fixme: Implement sp_button_new_from_action */
640 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
641 gtk_widget_show(b);
644 unsigned int shortcut = sp_shortcut_get_primary(verb);
645 if (shortcut) {
646 gchar key[256];
647 sp_ui_shortcut_string(shortcut, key);
648 gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
649 if ( t ) {
650 gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, tip, 0 );
651 }
652 g_free(tip);
653 } else {
654 if ( t ) {
655 gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, action->tip, 0 );
656 }
657 }
659 return b;
660 }
663 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
664 {
665 SPAction* targetAction = SP_ACTION(user_data);
666 if ( targetAction ) {
667 sp_action_perform( targetAction, NULL );
668 }
669 }
671 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
672 {
673 if ( data ) {
674 GtkAction* act = GTK_ACTION(data);
675 gtk_action_set_sensitive( act, sensitive );
676 }
677 }
679 static SPActionEventVector action_event_vector = {
680 {NULL},
681 NULL,
682 NULL,
683 sp_action_action_set_sensitive,
684 NULL,
685 NULL
686 };
688 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
689 {
690 GtkAction* act = 0;
692 SPAction* targetAction = verb->get_action(view);
693 InkAction* inky = ink_action_new( verb->get_id(), _(verb->get_name()), verb->get_tip(), verb->get_image(), size );
694 act = GTK_ACTION(inky);
695 gtk_action_set_sensitive( act, targetAction->sensitive );
697 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
699 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
700 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
702 return act;
703 }
705 Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop )
706 {
707 Inkscape::UI::View::View *view = desktop;
708 gint verbsToUse[] = {
709 // disabled until we have icons for them:
710 //find
711 //SP_VERB_EDIT_TILE,
712 //SP_VERB_EDIT_UNTILE,
713 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
714 SP_VERB_DIALOG_DISPLAY,
715 SP_VERB_DIALOG_FILL_STROKE,
716 SP_VERB_DIALOG_NAMEDVIEW,
717 SP_VERB_DIALOG_TEXT,
718 SP_VERB_DIALOG_XML_EDITOR,
719 SP_VERB_EDIT_CLONE,
720 SP_VERB_EDIT_COPY,
721 SP_VERB_EDIT_CUT,
722 SP_VERB_EDIT_DUPLICATE,
723 SP_VERB_EDIT_PASTE,
724 SP_VERB_EDIT_REDO,
725 SP_VERB_EDIT_UNDO,
726 SP_VERB_EDIT_UNLINK_CLONE,
727 SP_VERB_FILE_EXPORT,
728 SP_VERB_FILE_IMPORT,
729 SP_VERB_FILE_NEW,
730 SP_VERB_FILE_OPEN,
731 SP_VERB_FILE_PRINT,
732 SP_VERB_FILE_SAVE,
733 SP_VERB_OBJECT_TO_CURVE,
734 SP_VERB_SELECTION_GROUP,
735 SP_VERB_SELECTION_OUTLINE,
736 SP_VERB_SELECTION_UNGROUP,
737 SP_VERB_ZOOM_1_1,
738 SP_VERB_ZOOM_1_2,
739 SP_VERB_ZOOM_2_1,
740 SP_VERB_ZOOM_DRAWING,
741 SP_VERB_ZOOM_IN,
742 SP_VERB_ZOOM_NEXT,
743 SP_VERB_ZOOM_OUT,
744 SP_VERB_ZOOM_PAGE,
745 SP_VERB_ZOOM_PAGE_WIDTH,
746 SP_VERB_ZOOM_PREV,
747 SP_VERB_ZOOM_SELECTION,
748 };
750 Inkscape::IconSize toolboxSize = prefToSize("toolbox", "small");
752 static std::map<SPDesktop*, Glib::RefPtr<Gtk::ActionGroup> > groups;
753 Glib::RefPtr<Gtk::ActionGroup> mainActions;
754 if ( groups.find(desktop) != groups.end() ) {
755 mainActions = groups[desktop];
756 }
758 if ( !mainActions ) {
759 mainActions = Gtk::ActionGroup::create("main");
760 groups[desktop] = mainActions;
761 }
763 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
764 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
765 if ( verb ) {
766 if (!mainActions->get_action(verb->get_id())) {
767 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
768 mainActions->add(Glib::wrap(act));
769 }
770 }
771 }
773 if ( !mainActions->get_action("ToolZoom") ) {
774 GtkTooltips *tt = gtk_tooltips_new();
775 for ( guint i = 0; i < G_N_ELEMENTS(tools) && tools[i].type_name; i++ ) {
776 Glib::RefPtr<VerbAction> va = VerbAction::create(Inkscape::Verb::get(tools[i].verb), Inkscape::Verb::get(tools[i].doubleclick_verb), view, tt);
777 if ( va ) {
778 mainActions->add(va);
779 if ( i == 0 ) {
780 va->set_active(true);
781 }
782 }
783 }
784 }
787 return mainActions;
788 }
791 void handlebox_detached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
792 {
793 gtk_widget_set_size_request( widget,
794 widget->allocation.width,
795 widget->allocation.height );
796 }
798 void handlebox_attached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
799 {
800 gtk_widget_set_size_request( widget, -1, -1 );
801 }
805 GtkWidget *
806 sp_tool_toolbox_new()
807 {
808 GtkTooltips *tt = gtk_tooltips_new();
809 GtkWidget* tb = gtk_toolbar_new();
810 gtk_toolbar_set_orientation(GTK_TOOLBAR(tb), GTK_ORIENTATION_VERTICAL);
811 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(tb), TRUE);
813 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
814 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
816 gtk_widget_set_sensitive(tb, FALSE);
818 GtkWidget *hb = gtk_handle_box_new();
819 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
820 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
821 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
823 gtk_container_add(GTK_CONTAINER(hb), tb);
824 gtk_widget_show(GTK_WIDGET(tb));
826 sigc::connection* conn = new sigc::connection;
827 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
829 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
830 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
832 return hb;
833 }
835 GtkWidget *
836 sp_aux_toolbox_new()
837 {
838 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
840 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
842 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
844 gtk_widget_set_sensitive(tb, FALSE);
846 GtkWidget *hb = gtk_handle_box_new();
847 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
848 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
849 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
851 gtk_container_add(GTK_CONTAINER(hb), tb);
852 gtk_widget_show(GTK_WIDGET(tb));
854 sigc::connection* conn = new sigc::connection;
855 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
857 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
858 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
860 return hb;
861 }
863 //####################################
864 //# Commands Bar
865 //####################################
867 GtkWidget *
868 sp_commands_toolbox_new()
869 {
870 GtkWidget *tb = gtk_toolbar_new();
872 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
873 gtk_widget_set_sensitive(tb, FALSE);
875 GtkWidget *hb = gtk_handle_box_new();
876 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
877 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
878 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
880 gtk_container_add(GTK_CONTAINER(hb), tb);
881 gtk_widget_show(GTK_WIDGET(tb));
883 sigc::connection* conn = new sigc::connection;
884 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
886 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
887 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
889 return hb;
890 }
893 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
894 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
895 gchar const *path, gchar const *data, gdouble def,
896 GtkWidget *focusTarget,
897 GtkWidget *us,
898 GObject *dataKludge,
899 gboolean altx, gchar const *altx_mark,
900 gdouble lower, gdouble upper, gdouble step, gdouble page,
901 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
902 void (*callback)(GtkAdjustment *, GObject *),
903 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
904 {
905 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
906 lower, upper, step, page, page ) );
907 if (us) {
908 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
909 }
911 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
913 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
914 if ( shortLabel ) {
915 g_object_set( act, "short_label", shortLabel, NULL );
916 }
918 if ( (descrCount > 0) && descrLabels && descrValues ) {
919 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
920 }
922 if ( focusTarget ) {
923 ege_adjustment_action_set_focuswidget( act, focusTarget );
924 }
926 if ( altx && altx_mark ) {
927 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
928 }
930 if ( dataKludge ) {
931 g_object_set_data( dataKludge, data, adj );
932 }
934 // Using a cast just to make sure we pass in the right kind of function pointer
935 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
937 return act;
938 }
941 //####################################
942 //# node editing callbacks
943 //####################################
945 /**
946 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
947 */
948 static ShapeEditor *get_current_shape_editor()
949 {
950 if (!SP_ACTIVE_DESKTOP) {
951 return NULL;
952 }
954 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
956 if (!SP_IS_NODE_CONTEXT(event_context)) {
957 return NULL;
958 }
960 return SP_NODE_CONTEXT(event_context)->shape_editor;
961 }
964 void
965 sp_node_path_edit_add(void)
966 {
967 ShapeEditor *shape_editor = get_current_shape_editor();
968 if (shape_editor) shape_editor->add_node();
969 }
971 void
972 sp_node_path_edit_delete(void)
973 {
974 ShapeEditor *shape_editor = get_current_shape_editor();
975 if (shape_editor) shape_editor->delete_nodes_preserving_shape();
976 }
978 void
979 sp_node_path_edit_delete_segment(void)
980 {
981 ShapeEditor *shape_editor = get_current_shape_editor();
982 if (shape_editor) shape_editor->delete_segment();
983 }
985 void
986 sp_node_path_edit_break(void)
987 {
988 ShapeEditor *shape_editor = get_current_shape_editor();
989 if (shape_editor) shape_editor->break_at_nodes();
990 }
992 void
993 sp_node_path_edit_join(void)
994 {
995 ShapeEditor *shape_editor = get_current_shape_editor();
996 if (shape_editor) shape_editor->join_nodes();
997 }
999 void
1000 sp_node_path_edit_join_segment(void)
1001 {
1002 ShapeEditor *shape_editor = get_current_shape_editor();
1003 if (shape_editor) shape_editor->join_segments();
1004 }
1006 void
1007 sp_node_path_edit_toline(void)
1008 {
1009 ShapeEditor *shape_editor = get_current_shape_editor();
1010 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
1011 }
1013 void
1014 sp_node_path_edit_tocurve(void)
1015 {
1016 ShapeEditor *shape_editor = get_current_shape_editor();
1017 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
1018 }
1020 void
1021 sp_node_path_edit_cusp(void)
1022 {
1023 ShapeEditor *shape_editor = get_current_shape_editor();
1024 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
1025 }
1027 void
1028 sp_node_path_edit_smooth(void)
1029 {
1030 ShapeEditor *shape_editor = get_current_shape_editor();
1031 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
1032 }
1034 void
1035 sp_node_path_edit_symmetrical(void)
1036 {
1037 ShapeEditor *shape_editor = get_current_shape_editor();
1038 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
1039 }
1041 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
1042 bool show = gtk_toggle_action_get_active( act );
1043 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
1044 ShapeEditor *shape_editor = get_current_shape_editor();
1045 if (shape_editor) shape_editor->show_handles(show);
1046 }
1048 static void toggle_show_helperpath (GtkToggleAction *act, gpointer /*data*/) {
1049 bool show = gtk_toggle_action_get_active( act );
1050 prefs_set_int_attribute ("tools.nodes", "show_helperpath", show ? 1 : 0);
1051 ShapeEditor *shape_editor = get_current_shape_editor();
1052 if (shape_editor) shape_editor->show_helperpath(show);
1053 }
1055 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
1056 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
1057 }
1059 void sp_node_path_edit_clippath (GtkAction */*act*/, gpointer data) {
1060 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), true);
1061 }
1063 void sp_node_path_edit_maskpath (GtkAction */*act*/, gpointer data) {
1064 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), false);
1065 }
1067 /* is called when the node selection is modified */
1068 static void
1069 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
1070 {
1071 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
1072 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
1073 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
1074 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
1076 // quit if run by the attr_changed listener
1077 if (g_object_get_data( tbl, "freeze" )) {
1078 return;
1079 }
1081 // in turn, prevent listener from responding
1082 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1084 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1085 SPUnit const *unit = tracker->getActiveUnit();
1087 ShapeEditor *shape_editor = get_current_shape_editor();
1088 if (shape_editor && shape_editor->has_nodepath()) {
1089 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
1090 int n_selected = 0;
1091 if (nodepath) {
1092 n_selected = nodepath->numSelected();
1093 }
1095 if (n_selected == 0) {
1096 gtk_action_set_sensitive(xact, FALSE);
1097 gtk_action_set_sensitive(yact, FALSE);
1098 } else {
1099 gtk_action_set_sensitive(xact, TRUE);
1100 gtk_action_set_sensitive(yact, TRUE);
1101 NR::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
1102 NR::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
1104 if (n_selected == 1) {
1105 NR::Point sel_node = nodepath->singleSelectedCoords();
1106 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
1107 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[NR::X], *unit));
1108 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[NR::Y], *unit));
1109 }
1110 } else {
1111 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
1112 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
1113 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
1114 /* Note: Currently x and y will always have a value, even if the coordinates of the
1115 selected nodes don't coincide (in this case we use the coordinates of the center
1116 of the bounding box). So the entries are never set to zero. */
1117 // FIXME: Maybe we should clear the entry if several nodes are selected
1118 // instead of providing a kind of average value
1119 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
1120 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
1121 }
1122 }
1123 }
1124 } else {
1125 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
1126 gtk_action_set_sensitive(xact, FALSE);
1127 gtk_action_set_sensitive(yact, FALSE);
1128 }
1130 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1131 }
1133 static void
1134 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
1135 {
1136 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1138 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1139 SPUnit const *unit = tracker->getActiveUnit();
1141 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1142 prefs_set_double_attribute("tools.nodes", value_name, sp_units_get_pixels(adj->value, *unit));
1143 }
1145 // quit if run by the attr_changed listener
1146 if (g_object_get_data( tbl, "freeze" )) {
1147 return;
1148 }
1150 // in turn, prevent listener from responding
1151 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1153 ShapeEditor *shape_editor = get_current_shape_editor();
1154 if (shape_editor && shape_editor->has_nodepath()) {
1155 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
1156 if (!strcmp(value_name, "x")) {
1157 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::X);
1158 }
1159 if (!strcmp(value_name, "y")) {
1160 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::Y);
1161 }
1162 }
1164 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1165 }
1167 static void
1168 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
1169 {
1170 sp_node_path_value_changed(adj, tbl, "x");
1171 }
1173 static void
1174 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
1175 {
1176 sp_node_path_value_changed(adj, tbl, "y");
1177 }
1179 void
1180 sp_node_toolbox_sel_changed (Inkscape::Selection *selection, GObject *tbl)
1181 {
1182 {
1183 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_lpeedit" ) );
1184 SPItem *item = selection->singleItem();
1185 if (item && SP_IS_LPE_ITEM(item)) {
1186 if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(item))) {
1187 gtk_action_set_sensitive(w, TRUE);
1188 } else {
1189 gtk_action_set_sensitive(w, FALSE);
1190 }
1191 } else {
1192 gtk_action_set_sensitive(w, FALSE);
1193 }
1194 }
1196 {
1197 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_clippathedit" ) );
1198 SPItem *item = selection->singleItem();
1199 if (item && item->clip_ref && item->clip_ref->getObject()) {
1200 gtk_action_set_sensitive(w, TRUE);
1201 } else {
1202 gtk_action_set_sensitive(w, FALSE);
1203 }
1204 }
1206 {
1207 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_maskedit" ) );
1208 SPItem *item = selection->singleItem();
1209 if (item && item->mask_ref && item->mask_ref->getObject()) {
1210 gtk_action_set_sensitive(w, TRUE);
1211 } else {
1212 gtk_action_set_sensitive(w, FALSE);
1213 }
1214 }
1215 }
1217 void
1218 sp_node_toolbox_sel_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
1219 {
1220 sp_node_toolbox_sel_changed (selection, tbl);
1221 }
1225 //################################
1226 //## Node Editing Toolbox ##
1227 //################################
1229 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1230 {
1231 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1232 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1233 g_object_set_data( holder, "tracker", tracker );
1235 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
1237 {
1238 InkAction* inky = ink_action_new( "NodeInsertAction",
1239 _("Insert node"),
1240 _("Insert new nodes into selected segments"),
1241 "node_insert",
1242 secondarySize );
1243 g_object_set( inky, "short_label", _("Insert"), NULL );
1244 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
1245 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1246 }
1248 {
1249 InkAction* inky = ink_action_new( "NodeDeleteAction",
1250 _("Delete node"),
1251 _("Delete selected nodes"),
1252 "node_delete",
1253 secondarySize );
1254 g_object_set( inky, "short_label", _("Delete"), NULL );
1255 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
1256 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1257 }
1259 {
1260 InkAction* inky = ink_action_new( "NodeJoinAction",
1261 _("Join endnodes"),
1262 _("Join selected endnodes"),
1263 "node_join",
1264 secondarySize );
1265 g_object_set( inky, "short_label", _("Join"), NULL );
1266 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1267 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1268 }
1270 {
1271 InkAction* inky = ink_action_new( "NodeBreakAction",
1272 _("Break nodes"),
1273 _("Break path at selected nodes"),
1274 "node_break",
1275 secondarySize );
1276 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1277 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1278 }
1281 {
1282 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1283 _("Join with segment"),
1284 _("Join selected endnodes with a new segment"),
1285 "node_join_segment",
1286 secondarySize );
1287 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1288 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1289 }
1291 {
1292 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1293 _("Delete segment"),
1294 _("Delete segment between two non-endpoint nodes"),
1295 "node_delete_segment",
1296 secondarySize );
1297 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1298 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1299 }
1301 {
1302 InkAction* inky = ink_action_new( "NodeCuspAction",
1303 _("Node Cusp"),
1304 _("Make selected nodes corner"),
1305 "node_cusp",
1306 secondarySize );
1307 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1308 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1309 }
1311 {
1312 InkAction* inky = ink_action_new( "NodeSmoothAction",
1313 _("Node Smooth"),
1314 _("Make selected nodes smooth"),
1315 "node_smooth",
1316 secondarySize );
1317 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1318 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1319 }
1321 {
1322 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1323 _("Node Symmetric"),
1324 _("Make selected nodes symmetric"),
1325 "node_symmetric",
1326 secondarySize );
1327 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1328 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1329 }
1331 {
1332 InkAction* inky = ink_action_new( "NodeLineAction",
1333 _("Node Line"),
1334 _("Make selected segments lines"),
1335 "node_line",
1336 secondarySize );
1337 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1338 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1339 }
1341 {
1342 InkAction* inky = ink_action_new( "NodeCurveAction",
1343 _("Node Curve"),
1344 _("Make selected segments curves"),
1345 "node_curve",
1346 secondarySize );
1347 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1348 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1349 }
1351 {
1352 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1353 _("Show Handles"),
1354 _("Show the Bezier handles of selected nodes"),
1355 "nodes_show_handles",
1356 Inkscape::ICON_SIZE_DECORATION );
1357 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1358 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1359 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1360 }
1362 {
1363 InkToggleAction* act = ink_toggle_action_new( "NodesShowHelperpath",
1364 _("Show Outline"),
1365 _("Show the outline of the path"),
1366 "nodes_show_helperpath",
1367 Inkscape::ICON_SIZE_DECORATION );
1368 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1369 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_helperpath), desktop );
1370 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_helperpath", 0 ) );
1371 }
1373 {
1374 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1375 _("Next path effect parameter"),
1376 _("Show next path effect parameter for editing"),
1377 "edit_next_parameter",
1378 Inkscape::ICON_SIZE_DECORATION );
1379 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1380 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1381 g_object_set_data( holder, "nodes_lpeedit", inky);
1382 }
1384 {
1385 InkAction* inky = ink_action_new( "ObjectEditClipPathAction",
1386 _("Edit clipping path"),
1387 _("Edit the clipping path of the object"),
1388 "nodeedit-clippath",
1389 Inkscape::ICON_SIZE_DECORATION );
1390 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_clippath), desktop );
1391 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1392 g_object_set_data( holder, "nodes_clippathedit", inky);
1393 }
1395 {
1396 InkAction* inky = ink_action_new( "ObjectEditMaskPathAction",
1397 _("Edit mask path"),
1398 _("Edit the mask of the object"),
1399 "nodeedit-mask",
1400 Inkscape::ICON_SIZE_DECORATION );
1401 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_maskpath), desktop );
1402 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1403 g_object_set_data( holder, "nodes_maskedit", inky);
1404 }
1406 /* X coord of selected node(s) */
1407 {
1408 EgeAdjustmentAction* eact = 0;
1409 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1410 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1411 eact = create_adjustment_action( "NodeXAction",
1412 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1413 "tools.nodes", "Xcoord", 0,
1414 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1415 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1416 labels, values, G_N_ELEMENTS(labels),
1417 sp_node_path_x_value_changed );
1418 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1419 g_object_set_data( holder, "nodes_x_action", eact );
1420 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1421 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1422 }
1424 /* Y coord of selected node(s) */
1425 {
1426 EgeAdjustmentAction* eact = 0;
1427 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1428 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1429 eact = create_adjustment_action( "NodeYAction",
1430 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1431 "tools.nodes", "Ycoord", 0,
1432 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1433 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1434 labels, values, G_N_ELEMENTS(labels),
1435 sp_node_path_y_value_changed );
1436 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1437 g_object_set_data( holder, "nodes_y_action", eact );
1438 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1439 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1440 }
1442 // add the units menu
1443 {
1444 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1445 gtk_action_group_add_action( mainActions, act );
1446 }
1449 sp_node_toolbox_sel_changed(sp_desktop_selection(desktop), holder);
1451 //watch selection
1452 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
1454 sigc::connection *c_selection_changed =
1455 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
1456 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_changed), (GObject*)holder)));
1457 pool->add_connection ("selection-changed", c_selection_changed);
1459 sigc::connection *c_selection_modified =
1460 new sigc::connection (sp_desktop_selection (desktop)->connectModified
1461 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_modified), (GObject*)holder)));
1462 pool->add_connection ("selection-modified", c_selection_modified);
1464 sigc::connection *c_subselection_changed =
1465 new sigc::connection (desktop->connectToolSubselectionChanged
1466 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_coord_changed), (GObject*)holder)));
1467 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
1469 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool);
1471 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1472 } // end of sp_node_toolbox_prep()
1475 //########################
1476 //## Zoom Toolbox ##
1477 //########################
1479 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1480 {
1481 // no custom GtkAction setup needed
1482 } // end of sp_zoom_toolbox_prep()
1484 void
1485 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1486 {
1487 toolbox_set_desktop(toolbox,
1488 desktop,
1489 setup_tool_toolbox,
1490 update_tool_toolbox,
1491 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1492 "event_context_connection")));
1493 }
1496 void
1497 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1498 {
1499 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)),
1500 desktop,
1501 setup_aux_toolbox,
1502 update_aux_toolbox,
1503 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1504 "event_context_connection")));
1505 }
1507 void
1508 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1509 {
1510 toolbox_set_desktop(toolbox,
1511 desktop,
1512 setup_commands_toolbox,
1513 update_commands_toolbox,
1514 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1515 "event_context_connection")));
1516 }
1518 static void
1519 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1520 {
1521 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1522 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1524 if (old_desktop) {
1525 GList *children, *iter;
1527 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1528 for ( iter = children ; iter ; iter = iter->next ) {
1529 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1530 }
1531 g_list_free(children);
1532 }
1534 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1536 if (desktop) {
1537 gtk_widget_set_sensitive(toolbox, TRUE);
1538 setup_func(toolbox, desktop);
1539 update_func(desktop, desktop->event_context, toolbox);
1540 *conn = desktop->connectEventContextChanged
1541 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1542 } else {
1543 gtk_widget_set_sensitive(toolbox, FALSE);
1544 }
1546 } // end of toolbox_set_desktop()
1549 static void
1550 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1551 {
1552 gchar const * descr =
1553 "<ui>"
1554 " <toolbar name='ToolToolbar'>"
1555 " <toolitem action='ToolSelector' />"
1556 " <toolitem action='ToolNode' />"
1557 " <toolitem action='ToolTweak' />"
1558 " <toolitem action='ToolZoom' />"
1559 " <toolitem action='ToolRect' />"
1560 " <toolitem action='Tool3DBox' />"
1561 " <toolitem action='ToolArc' />"
1562 " <toolitem action='ToolStar' />"
1563 " <toolitem action='ToolSpiral' />"
1564 " <toolitem action='ToolPencil' />"
1565 " <toolitem action='ToolPen' />"
1566 " <toolitem action='ToolCalligraphic' />"
1567 " <toolitem action='ToolEraser' />"
1568 " <toolitem action='ToolPaintBucket' />"
1569 " <toolitem action='ToolText' />"
1570 " <toolitem action='ToolConnector' />"
1571 " <toolitem action='ToolGradient' />"
1572 " <toolitem action='ToolDropper' />"
1573 " </toolbar>"
1574 "</ui>";
1575 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1576 GtkUIManager* mgr = gtk_ui_manager_new();
1577 GError* errVal = 0;
1579 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1580 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1582 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/ToolToolbar" );
1583 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1584 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1585 }
1586 Inkscape::IconSize toolboxSize = prefToSize("toolbox.tools", "small");
1587 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1589 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_VERTICAL);
1590 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
1592 g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
1594 GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
1595 if ( child ) {
1596 gtk_container_remove( GTK_CONTAINER(toolbox), child );
1597 }
1599 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1600 // Inkscape::IconSize toolboxSize = prefToSize("toolbox.tools", "small");
1601 }
1604 static void
1605 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget */*toolbox*/ )
1606 {
1607 gchar const *const tname = ( eventcontext
1608 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1609 : NULL );
1610 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1612 for (int i = 0 ; tools[i].type_name ; i++ ) {
1613 Glib::RefPtr<Gtk::Action> act = mainActions->get_action( Inkscape::Verb::get(tools[i].verb)->get_id() );
1614 if ( act ) {
1615 bool setActive = tname && !strcmp(tname, tools[i].type_name);
1616 Glib::RefPtr<VerbAction> verbAct = Glib::RefPtr<VerbAction>::cast_dynamic(act);
1617 if ( verbAct ) {
1618 verbAct->set_active(setActive);
1619 }
1620 }
1621 }
1622 }
1624 static void
1625 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1626 {
1627 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1628 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1629 GtkUIManager* mgr = gtk_ui_manager_new();
1630 GError* errVal = 0;
1631 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1632 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1634 std::map<std::string, GtkWidget*> dataHolders;
1636 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1637 if ( aux_toolboxes[i].prep_func ) {
1638 // converted to GtkActions and UIManager
1640 GtkWidget* kludge = gtk_toolbar_new();
1641 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1642 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1643 dataHolders[aux_toolboxes[i].type_name] = kludge;
1644 aux_toolboxes[i].prep_func( desktop, mainActions->gobj(), G_OBJECT(kludge) );
1645 } else {
1647 GtkWidget *sub_toolbox = 0;
1648 if (aux_toolboxes[i].create_func == NULL)
1649 sub_toolbox = sp_empty_toolbox_new(desktop);
1650 else {
1651 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1652 }
1654 gtk_size_group_add_widget( grouper, sub_toolbox );
1656 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1657 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1659 }
1660 }
1662 // Second pass to create toolbars *after* all GtkActions are created
1663 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1664 if ( aux_toolboxes[i].prep_func ) {
1665 // converted to GtkActions and UIManager
1667 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1669 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1670 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1672 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1673 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1674 g_free( tmp );
1675 tmp = 0;
1677 Inkscape::IconSize toolboxSize = prefToSize("toolbox", "small");
1678 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1679 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1680 }
1681 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1684 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1686 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1687 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, _(aux_toolboxes[i].swatch_tip) );
1688 swatch->setDesktop( desktop );
1689 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1690 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1691 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1692 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 );
1693 }
1695 gtk_widget_show_all( holder );
1696 sp_set_font_size_smaller( holder );
1698 gtk_size_group_add_widget( grouper, holder );
1700 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1701 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1702 }
1703 }
1705 g_object_unref( G_OBJECT(grouper) );
1706 }
1708 static void
1709 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1710 {
1711 gchar const *tname = ( eventcontext
1712 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1713 : NULL );
1714 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1715 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1716 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1717 gtk_widget_show_all(sub_toolbox);
1718 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1719 } else {
1720 gtk_widget_hide(sub_toolbox);
1721 }
1722 }
1723 }
1725 static void
1726 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1727 {
1728 gchar const * descr =
1729 "<ui>"
1730 " <toolbar name='CommandsToolbar'>"
1731 " <toolitem action='FileNew' />"
1732 " <toolitem action='FileOpen' />"
1733 " <toolitem action='FileSave' />"
1734 " <toolitem action='FilePrint' />"
1735 " <separator />"
1736 " <toolitem action='FileImport' />"
1737 " <toolitem action='FileExport' />"
1738 " <separator />"
1739 " <toolitem action='EditUndo' />"
1740 " <toolitem action='EditRedo' />"
1741 " <separator />"
1742 " <toolitem action='EditCopy' />"
1743 " <toolitem action='EditCut' />"
1744 " <toolitem action='EditPaste' />"
1745 " <separator />"
1746 " <toolitem action='ZoomSelection' />"
1747 " <toolitem action='ZoomDrawing' />"
1748 " <toolitem action='ZoomPage' />"
1749 " <separator />"
1750 " <toolitem action='EditDuplicate' />"
1751 " <toolitem action='EditClone' />"
1752 " <toolitem action='EditUnlinkClone' />"
1753 " <separator />"
1754 " <toolitem action='SelectionGroup' />"
1755 " <toolitem action='SelectionUnGroup' />"
1756 " <separator />"
1757 " <toolitem action='DialogFillStroke' />"
1758 " <toolitem action='DialogText' />"
1759 " <toolitem action='DialogXMLEditor' />"
1760 " <toolitem action='DialogAlignDistribute' />"
1761 " <separator />"
1762 " <toolitem action='DialogPreferences' />"
1763 " <toolitem action='DialogDocumentProperties' />"
1764 " </toolbar>"
1765 "</ui>";
1766 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1769 GtkUIManager* mgr = gtk_ui_manager_new();
1770 GError* errVal = 0;
1772 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1773 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1775 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1776 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1777 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1778 }
1780 Inkscape::IconSize toolboxSize = prefToSize("toolbox", "small");
1781 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1783 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_HORIZONTAL);
1784 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
1787 g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
1789 GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
1790 if ( child ) {
1791 gtk_container_remove( GTK_CONTAINER(toolbox), child );
1792 }
1794 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1795 }
1797 static void
1798 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1799 {
1800 }
1802 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1803 {
1804 gtk_widget_show(toolbox_toplevel);
1805 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1807 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1808 if (!shown_toolbox) {
1809 return;
1810 }
1811 gtk_widget_show(toolbox);
1813 gtk_widget_show_all(shown_toolbox);
1814 }
1816 static GtkWidget *
1817 sp_empty_toolbox_new(SPDesktop *desktop)
1818 {
1819 GtkWidget *tbl = gtk_toolbar_new();
1820 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1821 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1823 gtk_widget_show_all(tbl);
1824 sp_set_font_size_smaller (tbl);
1826 return tbl;
1827 }
1829 #define MODE_LABEL_WIDTH 70
1831 //########################
1832 //## Star ##
1833 //########################
1835 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1836 {
1837 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1839 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1840 // do not remember prefs if this call is initiated by an undo change, because undoing object
1841 // creation sets bogus values to its attributes before it is deleted
1842 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1843 }
1845 // quit if run by the attr_changed listener
1846 if (g_object_get_data( dataKludge, "freeze" )) {
1847 return;
1848 }
1850 // in turn, prevent listener from responding
1851 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1853 bool modmade = false;
1855 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1856 GSList const *items = selection->itemList();
1857 for (; items != NULL; items = items->next) {
1858 if (SP_IS_STAR((SPItem *) items->data)) {
1859 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1860 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1861 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1862 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1863 + M_PI / (gint)adj->value));
1864 SP_OBJECT((SPItem *) items->data)->updateRepr();
1865 modmade = true;
1866 }
1867 }
1868 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1869 _("Star: Change number of corners"));
1871 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1872 }
1874 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1875 {
1876 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1878 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1879 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1880 }
1882 // quit if run by the attr_changed listener
1883 if (g_object_get_data( dataKludge, "freeze" )) {
1884 return;
1885 }
1887 // in turn, prevent listener from responding
1888 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1890 bool modmade = false;
1891 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1892 GSList const *items = selection->itemList();
1893 for (; items != NULL; items = items->next) {
1894 if (SP_IS_STAR((SPItem *) items->data)) {
1895 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1897 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1898 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1899 if (r2 < r1) {
1900 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1901 } else {
1902 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1903 }
1905 SP_OBJECT((SPItem *) items->data)->updateRepr();
1906 modmade = true;
1907 }
1908 }
1910 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1911 _("Star: Change spoke ratio"));
1913 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1914 }
1916 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1917 {
1918 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1919 bool flat = ege_select_one_action_get_active( act ) == 0;
1921 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1922 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1923 flat ? "true" : "false" );
1924 }
1926 // quit if run by the attr_changed listener
1927 if (g_object_get_data( dataKludge, "freeze" )) {
1928 return;
1929 }
1931 // in turn, prevent listener from responding
1932 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1934 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1935 GSList const *items = selection->itemList();
1936 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1937 bool modmade = false;
1939 if ( prop_action ) {
1940 gtk_action_set_sensitive( prop_action, !flat );
1941 }
1943 for (; items != NULL; items = items->next) {
1944 if (SP_IS_STAR((SPItem *) items->data)) {
1945 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1946 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1947 SP_OBJECT((SPItem *) items->data)->updateRepr();
1948 modmade = true;
1949 }
1950 }
1952 if (modmade) {
1953 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1954 flat ? _("Make polygon") : _("Make star"));
1955 }
1957 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1958 }
1960 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1961 {
1962 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1964 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1965 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1966 }
1968 // quit if run by the attr_changed listener
1969 if (g_object_get_data( dataKludge, "freeze" )) {
1970 return;
1971 }
1973 // in turn, prevent listener from responding
1974 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1976 bool modmade = false;
1978 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1979 GSList const *items = selection->itemList();
1980 for (; items != NULL; items = items->next) {
1981 if (SP_IS_STAR((SPItem *) items->data)) {
1982 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1983 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1984 SP_OBJECT(items->data)->updateRepr();
1985 modmade = true;
1986 }
1987 }
1988 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1989 _("Star: Change rounding"));
1991 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1992 }
1994 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1995 {
1996 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1998 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1999 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
2000 }
2002 // quit if run by the attr_changed listener
2003 if (g_object_get_data( dataKludge, "freeze" )) {
2004 return;
2005 }
2007 // in turn, prevent listener from responding
2008 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2010 bool modmade = false;
2012 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2013 GSList const *items = selection->itemList();
2014 for (; items != NULL; items = items->next) {
2015 if (SP_IS_STAR((SPItem *) items->data)) {
2016 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2017 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
2018 SP_OBJECT(items->data)->updateRepr();
2019 modmade = true;
2020 }
2021 }
2022 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2023 _("Star: Change randomization"));
2025 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2026 }
2029 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2030 gchar const */*old_value*/, gchar const */*new_value*/,
2031 bool /*is_interactive*/, gpointer data)
2032 {
2033 GtkWidget *tbl = GTK_WIDGET(data);
2035 // quit if run by the _changed callbacks
2036 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2037 return;
2038 }
2040 // in turn, prevent callbacks from responding
2041 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2043 GtkAdjustment *adj = 0;
2045 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
2046 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
2048 if (!strcmp(name, "inkscape:randomized")) {
2049 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
2050 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
2051 } else if (!strcmp(name, "inkscape:rounded")) {
2052 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
2053 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
2054 } else if (!strcmp(name, "inkscape:flatsided")) {
2055 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
2056 char const *flatsides = repr->attribute("inkscape:flatsided");
2057 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
2058 if ( flatsides && !strcmp(flatsides,"false") ) {
2059 ege_select_one_action_set_active( flat_action, 1 );
2060 gtk_action_set_sensitive( prop_action, TRUE );
2061 } else {
2062 ege_select_one_action_set_active( flat_action, 0 );
2063 gtk_action_set_sensitive( prop_action, FALSE );
2064 }
2065 } else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) {
2066 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
2067 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
2068 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
2069 if (r2 < r1) {
2070 gtk_adjustment_set_value(adj, r2/r1);
2071 } else {
2072 gtk_adjustment_set_value(adj, r1/r2);
2073 }
2074 } else if (!strcmp(name, "sodipodi:sides")) {
2075 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
2076 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
2077 }
2079 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2080 }
2083 static Inkscape::XML::NodeEventVector star_tb_repr_events =
2084 {
2085 NULL, /* child_added */
2086 NULL, /* child_removed */
2087 star_tb_event_attr_changed,
2088 NULL, /* content_changed */
2089 NULL /* order_changed */
2090 };
2093 /**
2094 * \param selection Should not be NULL.
2095 */
2096 static void
2097 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2098 {
2099 int n_selected = 0;
2100 Inkscape::XML::Node *repr = NULL;
2102 purge_repr_listener( tbl, tbl );
2104 for (GSList const *items = selection->itemList();
2105 items != NULL;
2106 items = items->next)
2107 {
2108 if (SP_IS_STAR((SPItem *) items->data)) {
2109 n_selected++;
2110 repr = SP_OBJECT_REPR((SPItem *) items->data);
2111 }
2112 }
2114 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2116 if (n_selected == 0) {
2117 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2118 } else if (n_selected == 1) {
2119 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2121 if (repr) {
2122 g_object_set_data( tbl, "repr", repr );
2123 Inkscape::GC::anchor(repr);
2124 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
2125 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
2126 }
2127 } else {
2128 // FIXME: implement averaging of all parameters for multiple selected stars
2129 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2130 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2131 }
2132 }
2135 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
2136 {
2137 // FIXME: in this and all other _default functions, set some flag telling the value_changed
2138 // callbacks to lump all the changes for all selected objects in one undo step
2140 GtkAdjustment *adj = 0;
2142 // fixme: make settable in prefs!
2143 gint mag = 5;
2144 gdouble prop = 0.5;
2145 gboolean flat = FALSE;
2146 gdouble randomized = 0;
2147 gdouble rounded = 0;
2149 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
2150 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
2152 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
2153 gtk_action_set_sensitive( sb2, !flat );
2155 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
2156 gtk_adjustment_set_value(adj, mag);
2157 gtk_adjustment_value_changed(adj);
2159 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
2160 gtk_adjustment_set_value(adj, prop);
2161 gtk_adjustment_value_changed(adj);
2163 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
2164 gtk_adjustment_set_value(adj, rounded);
2165 gtk_adjustment_value_changed(adj);
2167 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
2168 gtk_adjustment_set_value(adj, randomized);
2169 gtk_adjustment_value_changed(adj);
2170 }
2173 void
2174 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
2175 {
2176 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
2177 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
2178 GtkWidget *l = gtk_label_new(NULL);
2179 gtk_label_set_markup(GTK_LABEL(l), title);
2180 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
2181 if ( GTK_IS_TOOLBAR(tbl) ) {
2182 gtk_toolbar_append_widget( GTK_TOOLBAR(tbl), boxl, "", "" );
2183 } else {
2184 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
2185 }
2186 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
2187 }
2190 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2191 {
2192 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
2194 {
2195 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
2196 ege_output_action_set_use_markup( act, TRUE );
2197 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2198 g_object_set_data( holder, "mode_action", act );
2199 }
2201 {
2202 EgeAdjustmentAction* eact = 0;
2203 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
2204 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
2206 /* Flatsided checkbox */
2207 {
2208 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2210 GtkTreeIter iter;
2211 gtk_list_store_append( model, &iter );
2212 gtk_list_store_set( model, &iter,
2213 0, _("Polygon"),
2214 1, _("Regular polygon (with one handle) instead of a star"),
2215 2, "star_flat",
2216 -1 );
2218 gtk_list_store_append( model, &iter );
2219 gtk_list_store_set( model, &iter,
2220 0, _("Star"),
2221 1, _("Star instead of a regular polygon (with one handle)"),
2222 2, "star_angled",
2223 -1 );
2225 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
2226 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2227 g_object_set_data( holder, "flat_action", act );
2229 ege_select_one_action_set_appearance( act, "full" );
2230 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2231 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2232 ege_select_one_action_set_icon_column( act, 2 );
2233 ege_select_one_action_set_icon_size( act, secondarySize );
2234 ege_select_one_action_set_tooltip_column( act, 1 );
2236 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
2237 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
2238 }
2240 /* Magnitude */
2241 {
2242 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
2243 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
2244 eact = create_adjustment_action( "MagnitudeAction",
2245 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
2246 "tools.shapes.star", "magnitude", 3,
2247 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2248 3, 1024, 1, 5,
2249 labels, values, G_N_ELEMENTS(labels),
2250 sp_stb_magnitude_value_changed,
2251 1.0, 0 );
2252 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2253 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2254 }
2256 /* Spoke ratio */
2257 {
2258 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
2259 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
2260 eact = create_adjustment_action( "SpokeAction",
2261 _("Spoke ratio"), _("Spoke ratio:"),
2262 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
2263 // Base radius is the same for the closest handle.
2264 _("Base radius to tip radius ratio"),
2265 "tools.shapes.star", "proportion", 0.5,
2266 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2267 0.01, 1.0, 0.01, 0.1,
2268 labels, values, G_N_ELEMENTS(labels),
2269 sp_stb_proportion_value_changed );
2270 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2271 g_object_set_data( holder, "prop_action", eact );
2272 }
2274 if ( !isFlatSided ) {
2275 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2276 } else {
2277 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2278 }
2280 /* Roundedness */
2281 {
2282 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
2283 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
2284 eact = create_adjustment_action( "RoundednessAction",
2285 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
2286 "tools.shapes.star", "rounded", 0.0,
2287 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2288 -10.0, 10.0, 0.01, 0.1,
2289 labels, values, G_N_ELEMENTS(labels),
2290 sp_stb_rounded_value_changed );
2291 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2292 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2293 }
2295 /* Randomization */
2296 {
2297 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
2298 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
2299 eact = create_adjustment_action( "RandomizationAction",
2300 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
2301 "tools.shapes.star", "randomized", 0.0,
2302 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2303 -10.0, 10.0, 0.001, 0.01,
2304 labels, values, G_N_ELEMENTS(labels),
2305 sp_stb_randomized_value_changed, 0.1, 3 );
2306 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2307 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2308 }
2309 }
2311 {
2312 /* Reset */
2313 {
2314 GtkAction* act = gtk_action_new( "StarResetAction",
2315 _("Defaults"),
2316 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2317 GTK_STOCK_CLEAR );
2318 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
2319 gtk_action_group_add_action( mainActions, act );
2320 gtk_action_set_sensitive( act, TRUE );
2321 }
2322 }
2324 sigc::connection *connection = new sigc::connection(
2325 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
2326 );
2327 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2328 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2329 }
2332 //########################
2333 //## Rect ##
2334 //########################
2336 static void sp_rtb_sensitivize( GObject *tbl )
2337 {
2338 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
2339 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
2340 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
2342 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
2343 gtk_action_set_sensitive( not_rounded, FALSE );
2344 } else {
2345 gtk_action_set_sensitive( not_rounded, TRUE );
2346 }
2347 }
2350 static void
2351 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
2352 void (*setter)(SPRect *, gdouble))
2353 {
2354 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2356 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2357 SPUnit const *unit = tracker->getActiveUnit();
2359 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2360 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
2361 }
2363 // quit if run by the attr_changed listener
2364 if (g_object_get_data( tbl, "freeze" )) {
2365 return;
2366 }
2368 // in turn, prevent listener from responding
2369 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2371 bool modmade = false;
2372 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2373 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2374 if (SP_IS_RECT(items->data)) {
2375 if (adj->value != 0) {
2376 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2377 } else {
2378 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2379 }
2380 modmade = true;
2381 }
2382 }
2384 sp_rtb_sensitivize( tbl );
2386 if (modmade) {
2387 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2388 _("Change rectangle"));
2389 }
2391 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2392 }
2394 static void
2395 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2396 {
2397 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2398 }
2400 static void
2401 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2402 {
2403 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2404 }
2406 static void
2407 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2408 {
2409 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2410 }
2412 static void
2413 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2414 {
2415 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2416 }
2420 static void
2421 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2422 {
2423 GtkAdjustment *adj = 0;
2425 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2426 gtk_adjustment_set_value(adj, 0.0);
2427 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2428 gtk_adjustment_value_changed(adj);
2430 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2431 gtk_adjustment_set_value(adj, 0.0);
2432 gtk_adjustment_value_changed(adj);
2434 sp_rtb_sensitivize( obj );
2435 }
2437 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2438 gchar const */*old_value*/, gchar const */*new_value*/,
2439 bool /*is_interactive*/, gpointer data)
2440 {
2441 GObject *tbl = G_OBJECT(data);
2443 // quit if run by the _changed callbacks
2444 if (g_object_get_data( tbl, "freeze" )) {
2445 return;
2446 }
2448 // in turn, prevent callbacks from responding
2449 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2451 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2452 SPUnit const *unit = tracker->getActiveUnit();
2454 gpointer item = g_object_get_data( tbl, "item" );
2455 if (item && SP_IS_RECT(item)) {
2456 {
2457 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2458 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2459 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2460 }
2462 {
2463 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2464 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2465 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2466 }
2468 {
2469 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2470 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2471 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2472 }
2474 {
2475 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2476 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2477 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2478 }
2479 }
2481 sp_rtb_sensitivize( tbl );
2483 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2484 }
2487 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2488 NULL, /* child_added */
2489 NULL, /* child_removed */
2490 rect_tb_event_attr_changed,
2491 NULL, /* content_changed */
2492 NULL /* order_changed */
2493 };
2495 /**
2496 * \param selection should not be NULL.
2497 */
2498 static void
2499 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2500 {
2501 int n_selected = 0;
2502 Inkscape::XML::Node *repr = NULL;
2503 SPItem *item = NULL;
2505 if ( g_object_get_data( tbl, "repr" ) ) {
2506 g_object_set_data( tbl, "item", NULL );
2507 }
2508 purge_repr_listener( tbl, tbl );
2510 for (GSList const *items = selection->itemList();
2511 items != NULL;
2512 items = items->next) {
2513 if (SP_IS_RECT((SPItem *) items->data)) {
2514 n_selected++;
2515 item = (SPItem *) items->data;
2516 repr = SP_OBJECT_REPR(item);
2517 }
2518 }
2520 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2522 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2524 if (n_selected == 0) {
2525 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2527 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2528 gtk_action_set_sensitive(w, FALSE);
2529 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2530 gtk_action_set_sensitive(h, FALSE);
2532 } else if (n_selected == 1) {
2533 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2534 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2536 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2537 gtk_action_set_sensitive(w, TRUE);
2538 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2539 gtk_action_set_sensitive(h, TRUE);
2541 if (repr) {
2542 g_object_set_data( tbl, "repr", repr );
2543 g_object_set_data( tbl, "item", item );
2544 Inkscape::GC::anchor(repr);
2545 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2546 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2547 }
2548 } else {
2549 // FIXME: implement averaging of all parameters for multiple selected
2550 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2551 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2552 sp_rtb_sensitivize( tbl );
2553 }
2554 }
2557 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2558 {
2559 EgeAdjustmentAction* eact = 0;
2560 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
2562 {
2563 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2564 ege_output_action_set_use_markup( act, TRUE );
2565 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2566 g_object_set_data( holder, "mode_action", act );
2567 }
2569 // rx/ry units menu: create
2570 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2571 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2572 // fixme: add % meaning per cent of the width/height
2573 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2574 g_object_set_data( holder, "tracker", tracker );
2576 /* W */
2577 {
2578 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2579 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2580 eact = create_adjustment_action( "RectWidthAction",
2581 _("Width"), _("W:"), _("Width of rectangle"),
2582 "tools.shapes.rect", "width", 0,
2583 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2584 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2585 labels, values, G_N_ELEMENTS(labels),
2586 sp_rtb_width_value_changed );
2587 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2588 g_object_set_data( holder, "width_action", eact );
2589 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2590 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2591 }
2593 /* H */
2594 {
2595 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2596 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2597 eact = create_adjustment_action( "RectHeightAction",
2598 _("Height"), _("H:"), _("Height of rectangle"),
2599 "tools.shapes.rect", "height", 0,
2600 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2601 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2602 labels, values, G_N_ELEMENTS(labels),
2603 sp_rtb_height_value_changed );
2604 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2605 g_object_set_data( holder, "height_action", eact );
2606 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2607 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2608 }
2610 /* rx */
2611 {
2612 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2613 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2614 eact = create_adjustment_action( "RadiusXAction",
2615 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2616 "tools.shapes.rect", "rx", 0,
2617 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2618 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2619 labels, values, G_N_ELEMENTS(labels),
2620 sp_rtb_rx_value_changed);
2621 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2622 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2623 }
2625 /* ry */
2626 {
2627 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2628 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2629 eact = create_adjustment_action( "RadiusYAction",
2630 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2631 "tools.shapes.rect", "ry", 0,
2632 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2633 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2634 labels, values, G_N_ELEMENTS(labels),
2635 sp_rtb_ry_value_changed);
2636 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2637 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2638 }
2640 // add the units menu
2641 {
2642 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2643 gtk_action_group_add_action( mainActions, act );
2644 }
2646 /* Reset */
2647 {
2648 InkAction* inky = ink_action_new( "RectResetAction",
2649 _("Not rounded"),
2650 _("Make corners sharp"),
2651 "squared_corner",
2652 secondarySize );
2653 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2654 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2655 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2656 g_object_set_data( holder, "not_rounded", inky );
2657 }
2659 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2660 sp_rtb_sensitivize( holder );
2662 sigc::connection *connection = new sigc::connection(
2663 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2664 );
2665 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2666 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2667 }
2669 //########################
2670 //## 3D Box ##
2671 //########################
2673 // normalize angle so that it lies in the interval [0,360]
2674 static double box3d_normalize_angle (double a) {
2675 double angle = a + ((int) (a/360.0))*360;
2676 if (angle < 0) {
2677 angle += 360.0;
2678 }
2679 return angle;
2680 }
2682 static void
2683 box3d_set_button_and_adjustment(Persp3D *persp, Proj::Axis axis,
2684 GtkAdjustment *adj, GtkAction *act, GtkToggleAction *tact) {
2685 // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
2686 // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
2687 // are reset).
2688 bool is_infinite = !persp3d_VP_is_finite(persp, axis);
2690 if (is_infinite) {
2691 gtk_toggle_action_set_active(tact, TRUE);
2692 gtk_action_set_sensitive(act, TRUE);
2694 double angle = persp3d_get_infinite_angle(persp, axis);
2695 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
2696 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
2697 }
2698 } else {
2699 gtk_toggle_action_set_active(tact, FALSE);
2700 gtk_action_set_sensitive(act, FALSE);
2701 }
2702 }
2704 static void
2705 box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) {
2706 if (!persp_repr) {
2707 g_print ("No perspective given to box3d_resync_toolbar().\n");
2708 return;
2709 }
2711 GtkWidget *tbl = GTK_WIDGET(data);
2712 GtkAdjustment *adj = 0;
2713 GtkAction *act = 0;
2714 GtkToggleAction *tact = 0;
2715 Persp3D *persp = persp3d_get_from_repr(persp_repr);
2716 {
2717 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
2718 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
2719 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action;
2721 box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact);
2722 }
2723 {
2724 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_y"));
2725 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action"));
2726 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action;
2728 box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact);
2729 }
2730 {
2731 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_z"));
2732 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action"));
2733 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action;
2735 box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact);
2736 }
2737 }
2739 static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2740 gchar const */*old_value*/, gchar const */*new_value*/,
2741 bool /*is_interactive*/, gpointer data)
2742 {
2743 GtkWidget *tbl = GTK_WIDGET(data);
2745 // quit if run by the attr_changed listener
2746 // note: it used to work without the differently called freeze_ attributes (here and in
2747 // box3d_angle_value_changed()) but I now it doesn't so I'm leaving them in for now
2748 if (g_object_get_data(G_OBJECT(tbl), "freeze_angle")) {
2749 return;
2750 }
2752 // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling
2753 // sp_document_maybe_done() when the document is undo insensitive)
2754 g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(TRUE));
2756 // TODO: Only update the appropriate part of the toolbar
2757 // if (!strcmp(name, "inkscape:vp_z")) {
2758 box3d_resync_toolbar(repr, G_OBJECT(tbl));
2759 // }
2761 Persp3D *persp = persp3d_get_from_repr(repr);
2762 persp3d_update_box_reprs(persp);
2764 g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(FALSE));
2765 }
2767 static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
2768 {
2769 NULL, /* child_added */
2770 NULL, /* child_removed */
2771 box3d_persp_tb_event_attr_changed,
2772 NULL, /* content_changed */
2773 NULL /* order_changed */
2774 };
2776 /**
2777 * \param selection Should not be NULL.
2778 */
2779 // FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
2780 // Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
2781 static void
2782 box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2783 {
2784 // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
2785 // disable the angle entry fields for this direction (otherwise entering a value in them should only
2786 // update the perspectives with infinite VPs and leave the other ones untouched).
2788 Inkscape::XML::Node *persp_repr = NULL;
2789 purge_repr_listener(tbl, tbl);
2791 SPItem *item = selection->singleItem();
2792 if (item && SP_IS_BOX3D(item)) {
2793 // FIXME: Also deal with multiple selected boxes
2794 SPBox3D *box = SP_BOX3D(item);
2795 Persp3D *persp = box3d_get_perspective(box);
2796 persp_repr = SP_OBJECT_REPR(persp);
2797 if (persp_repr) {
2798 g_object_set_data(tbl, "repr", persp_repr);
2799 Inkscape::GC::anchor(persp_repr);
2800 sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl);
2801 sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
2802 }
2804 inkscape_active_document()->current_persp3d = persp3d_get_from_repr(persp_repr);
2805 prefs_set_string_attribute("tools.shapes.3dbox", "persp", persp_repr->attribute("id"));
2807 box3d_resync_toolbar(persp_repr, tbl);
2808 }
2809 }
2811 static void
2812 box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis)
2813 {
2814 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2815 SPDocument *document = sp_desktop_document(desktop);
2817 // quit if run by the attr_changed listener
2818 // note: it used to work without the differently called freeze_ attributes (here and in
2819 // box3d_persp_tb_event_attr_changed()) but I now it doesn't so I'm leaving them in for now
2820 if (g_object_get_data( dataKludge, "freeze_attr" )) {
2821 return;
2822 }
2824 // in turn, prevent listener from responding
2825 g_object_set_data(dataKludge, "freeze_angle", GINT_TO_POINTER(TRUE));
2827 //Persp3D *persp = document->current_persp3d;
2828 std::list<Persp3D *> sel_persps = sp_desktop_selection(desktop)->perspList();
2829 if (sel_persps.empty()) {
2830 // this can happen when the document is created; we silently ignore it
2831 return;
2832 }
2833 Persp3D *persp = sel_persps.front();
2835 persp->tmat.set_infinite_direction (axis, adj->value);
2836 SP_OBJECT(persp)->updateRepr();
2838 // TODO: use the correct axis here, too
2839 sp_document_maybe_done(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)"));
2841 g_object_set_data( dataKludge, "freeze_angle", GINT_TO_POINTER(FALSE) );
2842 }
2845 static void
2846 box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2847 {
2848 box3d_angle_value_changed(adj, dataKludge, Proj::X);
2849 }
2851 static void
2852 box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2853 {
2854 box3d_angle_value_changed(adj, dataKludge, Proj::Y);
2855 }
2857 static void
2858 box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2859 {
2860 box3d_angle_value_changed(adj, dataKludge, Proj::Z);
2861 }
2864 static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction */*box3d_angle*/, Proj::Axis axis )
2865 {
2866 // TODO: Take all selected perspectives into account
2867 std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList();
2868 if (sel_persps.empty()) {
2869 // this can happen when the document is created; we silently ignore it
2870 return;
2871 }
2872 Persp3D *persp = sel_persps.front();
2874 bool set_infinite = gtk_toggle_action_get_active(act);
2875 persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
2876 }
2878 static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2879 {
2880 box3d_vp_state_changed(act, box3d_angle, Proj::X);
2881 }
2883 static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2884 {
2885 box3d_vp_state_changed(act, box3d_angle, Proj::Y);
2886 }
2888 static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2889 {
2890 box3d_vp_state_changed(act, box3d_angle, Proj::Z);
2891 }
2893 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2894 {
2895 EgeAdjustmentAction* eact = 0;
2896 SPDocument *document = sp_desktop_document (desktop);
2897 Persp3D *persp = document->current_persp3d;
2899 EgeAdjustmentAction* box3d_angle_x = 0;
2900 EgeAdjustmentAction* box3d_angle_y = 0;
2901 EgeAdjustmentAction* box3d_angle_z = 0;
2903 /* Angle X */
2904 {
2905 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2906 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2907 eact = create_adjustment_action( "3DBoxAngleXAction",
2908 _("Angle in X direction"), _("Angle X:"),
2909 // Translators: PL is short for 'perspective line'
2910 _("Angle of PLs in X direction"),
2911 "tools.shapes.3dbox", "box3d_angle_x", 30,
2912 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
2913 -360.0, 360.0, 1.0, 10.0,
2914 labels, values, G_N_ELEMENTS(labels),
2915 box3d_angle_x_value_changed );
2916 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2917 g_object_set_data( holder, "box3d_angle_x_action", eact );
2918 box3d_angle_x = eact;
2919 }
2921 if (!persp3d_VP_is_finite(persp, Proj::X)) {
2922 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2923 } else {
2924 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2925 }
2928 /* VP X state */
2929 {
2930 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction",
2931 // Translators: VP is short for 'vanishing point'
2932 _("State of VP in X direction"),
2933 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2934 "toggle_vp_x",
2935 Inkscape::ICON_SIZE_DECORATION );
2936 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2937 g_object_set_data( holder, "box3d_vp_x_state_action", act );
2938 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x );
2939 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
2940 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
2941 }
2943 /* Angle Y */
2944 {
2945 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2946 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2947 eact = create_adjustment_action( "3DBoxAngleYAction",
2948 _("Angle in Y direction"), _("Angle Y:"),
2949 // Translators: PL is short for 'perspective line'
2950 _("Angle of PLs in Y direction"),
2951 "tools.shapes.3dbox", "box3d_angle_y", 30,
2952 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2953 -360.0, 360.0, 1.0, 10.0,
2954 labels, values, G_N_ELEMENTS(labels),
2955 box3d_angle_y_value_changed );
2956 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2957 g_object_set_data( holder, "box3d_angle_y_action", eact );
2958 box3d_angle_y = eact;
2959 }
2961 if (!persp3d_VP_is_finite(persp, Proj::Y)) {
2962 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2963 } else {
2964 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2965 }
2967 /* VP Y state */
2968 {
2969 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction",
2970 // Translators: VP is short for 'vanishing point'
2971 _("State of VP in Y direction"),
2972 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2973 "toggle_vp_y",
2974 Inkscape::ICON_SIZE_DECORATION );
2975 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2976 g_object_set_data( holder, "box3d_vp_y_state_action", act );
2977 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y );
2978 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
2979 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
2980 }
2982 /* Angle Z */
2983 {
2984 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2985 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2986 eact = create_adjustment_action( "3DBoxAngleZAction",
2987 _("Angle in Z direction"), _("Angle Z:"),
2988 // Translators: PL is short for 'perspective line'
2989 _("Angle of PLs in Z direction"),
2990 "tools.shapes.3dbox", "box3d_angle_z", 30,
2991 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2992 -360.0, 360.0, 1.0, 10.0,
2993 labels, values, G_N_ELEMENTS(labels),
2994 box3d_angle_z_value_changed );
2995 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2996 g_object_set_data( holder, "box3d_angle_z_action", eact );
2997 box3d_angle_z = eact;
2998 }
3000 if (!persp3d_VP_is_finite(persp, Proj::Z)) {
3001 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3002 } else {
3003 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3004 }
3006 /* VP Z state */
3007 {
3008 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction",
3009 // Translators: VP is short for 'vanishing point'
3010 _("State of VP in Z direction"),
3011 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
3012 "toggle_vp_z",
3013 Inkscape::ICON_SIZE_DECORATION );
3014 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3015 g_object_set_data( holder, "box3d_vp_z_state_action", act );
3016 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z );
3017 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
3018 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
3019 }
3021 sigc::connection *connection = new sigc::connection(
3022 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
3023 );
3024 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
3025 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
3026 }
3028 //########################
3029 //## Spiral ##
3030 //########################
3032 static void
3033 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
3034 {
3035 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3037 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3038 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
3039 }
3041 // quit if run by the attr_changed listener
3042 if (g_object_get_data( tbl, "freeze" )) {
3043 return;
3044 }
3046 // in turn, prevent listener from responding
3047 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3049 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
3051 bool modmade = false;
3052 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3053 items != NULL;
3054 items = items->next)
3055 {
3056 if (SP_IS_SPIRAL((SPItem *) items->data)) {
3057 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3058 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
3059 SP_OBJECT((SPItem *) items->data)->updateRepr();
3060 modmade = true;
3061 }
3062 }
3064 g_free(namespaced_name);
3066 if (modmade) {
3067 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
3068 _("Change spiral"));
3069 }
3071 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3072 }
3074 static void
3075 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
3076 {
3077 sp_spl_tb_value_changed(adj, tbl, "revolution");
3078 }
3080 static void
3081 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
3082 {
3083 sp_spl_tb_value_changed(adj, tbl, "expansion");
3084 }
3086 static void
3087 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
3088 {
3089 sp_spl_tb_value_changed(adj, tbl, "t0");
3090 }
3092 static void
3093 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
3094 {
3095 GtkWidget *tbl = GTK_WIDGET(obj);
3097 GtkAdjustment *adj;
3099 // fixme: make settable
3100 gdouble rev = 5;
3101 gdouble exp = 1.0;
3102 gdouble t0 = 0.0;
3104 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
3105 gtk_adjustment_set_value(adj, rev);
3106 gtk_adjustment_value_changed(adj);
3108 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
3109 gtk_adjustment_set_value(adj, exp);
3110 gtk_adjustment_value_changed(adj);
3112 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
3113 gtk_adjustment_set_value(adj, t0);
3114 gtk_adjustment_value_changed(adj);
3116 spinbutton_defocus(GTK_OBJECT(tbl));
3117 }
3120 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3121 gchar const */*old_value*/, gchar const */*new_value*/,
3122 bool /*is_interactive*/, gpointer data)
3123 {
3124 GtkWidget *tbl = GTK_WIDGET(data);
3126 // quit if run by the _changed callbacks
3127 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3128 return;
3129 }
3131 // in turn, prevent callbacks from responding
3132 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3134 GtkAdjustment *adj;
3135 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
3136 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
3138 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
3139 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
3141 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
3142 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
3144 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3145 }
3148 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
3149 NULL, /* child_added */
3150 NULL, /* child_removed */
3151 spiral_tb_event_attr_changed,
3152 NULL, /* content_changed */
3153 NULL /* order_changed */
3154 };
3156 static void
3157 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3158 {
3159 int n_selected = 0;
3160 Inkscape::XML::Node *repr = NULL;
3162 purge_repr_listener( tbl, tbl );
3164 for (GSList const *items = selection->itemList();
3165 items != NULL;
3166 items = items->next)
3167 {
3168 if (SP_IS_SPIRAL((SPItem *) items->data)) {
3169 n_selected++;
3170 repr = SP_OBJECT_REPR((SPItem *) items->data);
3171 }
3172 }
3174 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3176 if (n_selected == 0) {
3177 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3178 } else if (n_selected == 1) {
3179 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3181 if (repr) {
3182 g_object_set_data( tbl, "repr", repr );
3183 Inkscape::GC::anchor(repr);
3184 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
3185 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
3186 }
3187 } else {
3188 // FIXME: implement averaging of all parameters for multiple selected
3189 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3190 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3191 }
3192 }
3195 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3196 {
3197 EgeAdjustmentAction* eact = 0;
3198 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
3200 {
3201 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
3202 ege_output_action_set_use_markup( act, TRUE );
3203 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3204 g_object_set_data( holder, "mode_action", act );
3205 }
3207 /* Revolution */
3208 {
3209 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
3210 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
3211 eact = create_adjustment_action( "SpiralRevolutionAction",
3212 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
3213 "tools.shapes.spiral", "revolution", 3.0,
3214 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
3215 0.01, 1024.0, 0.1, 1.0,
3216 labels, values, G_N_ELEMENTS(labels),
3217 sp_spl_tb_revolution_value_changed, 1, 2);
3218 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3219 }
3221 /* Expansion */
3222 {
3223 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
3224 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
3225 eact = create_adjustment_action( "SpiralExpansionAction",
3226 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
3227 "tools.shapes.spiral", "expansion", 1.0,
3228 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3229 0.0, 1000.0, 0.01, 1.0,
3230 labels, values, G_N_ELEMENTS(labels),
3231 sp_spl_tb_expansion_value_changed);
3232 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3233 }
3235 /* T0 */
3236 {
3237 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
3238 gdouble values[] = {0, 0.5, 0.9};
3239 eact = create_adjustment_action( "SpiralT0Action",
3240 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
3241 "tools.shapes.spiral", "t0", 0.0,
3242 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3243 0.0, 0.999, 0.01, 1.0,
3244 labels, values, G_N_ELEMENTS(labels),
3245 sp_spl_tb_t0_value_changed);
3246 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3247 }
3249 /* Reset */
3250 {
3251 InkAction* inky = ink_action_new( "SpiralResetAction",
3252 _("Defaults"),
3253 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
3254 GTK_STOCK_CLEAR,
3255 secondarySize );
3256 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
3257 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3258 }
3261 sigc::connection *connection = new sigc::connection(
3262 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
3263 );
3264 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3265 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3266 }
3268 //########################
3269 //## Pen/Pencil ##
3270 //########################
3272 static void sp_pc_spiro_spline_mode_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
3273 {
3274 prefs_set_int_attribute("tools.freehand", "spiro-spline-mode", ege_select_one_action_get_active(act));
3275 }
3277 static void sp_add_spiro_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil)
3278 {
3279 // FIXME: No action is needed, we only want a simple label. But sp_toolbox_add_label() always
3280 // adds the label at the end of the toolbar, whence this workarund. How to avoid this?
3281 {
3282 EgeOutputAction* act = ege_output_action_new(
3283 tool_is_pencil ?
3284 "FreehandModeActionPencilTemp" :
3285 "FreehandModeActionPenTemp",
3286 _("<b>Mode:</b>"), "", 0 );
3287 ege_output_action_set_use_markup( act, TRUE );
3288 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3289 g_object_set_data( holder, "freehand_mode_action", act );
3290 }
3292 /* Freehand mode toggle buttons */
3293 {
3294 //gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
3295 //bool isSpiroMode = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
3296 guint spiroMode = prefs_get_int_attribute("tools.freehand", "spiro-spline-mode", 0);
3297 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
3299 {
3300 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3302 GtkTreeIter iter;
3303 gtk_list_store_append( model, &iter );
3304 gtk_list_store_set( model, &iter,
3305 0, _("Bézier"),
3306 1, _("Regular Bézier mode"),
3307 2, "bezier_mode",
3308 -1 );
3310 gtk_list_store_append( model, &iter );
3311 gtk_list_store_set( model, &iter,
3312 0, _("Spiro"),
3313 1, _("Spiro splines mode"),
3314 2, "spiro_splines_mode",
3315 -1 );
3317 EgeSelectOneAction* act = ege_select_one_action_new(tool_is_pencil ?
3318 "FreehandModeActionPencil" :
3319 "FreehandModeActionPen",
3320 (""), (""), NULL, GTK_TREE_MODEL(model) );
3321 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3322 g_object_set_data( holder, "freehande_mode_action", act );
3324 ege_select_one_action_set_appearance( act, "full" );
3325 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3326 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3327 ege_select_one_action_set_icon_column( act, 2 );
3328 ege_select_one_action_set_icon_size( act, secondarySize );
3329 ege_select_one_action_set_tooltip_column( act, 1 );
3331 ege_select_one_action_set_active( act, spiroMode);
3332 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_pc_spiro_spline_mode_changed), holder);
3333 }
3334 }
3335 }
3337 static void sp_freehand_change_shape(EgeSelectOneAction* act, GObject */*dataKludge*/) {
3338 gint shape = ege_select_one_action_get_active( act );
3339 prefs_set_int_attribute("tools.freehand", "shape", shape);
3340 }
3342 /**
3343 * \brief Generate the list of freehand advanced shape option entries.
3344 */
3345 GList * freehand_shape_dropdown_items_list() {
3346 GList *glist = NULL;
3348 glist = g_list_append (glist, _("None"));
3349 glist = g_list_append (glist, _("Clipboard"));
3350 glist = g_list_append (glist, _("Crescendo"));
3351 glist = g_list_append (glist, _("Decrescendo"));
3353 return glist;
3354 }
3356 static void
3357 sp_freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) {
3358 /*advanced shape options */
3359 {
3360 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
3362 GList* items = 0;
3363 gint count = 0;
3364 for ( items = freehand_shape_dropdown_items_list(); items ; items = g_list_next(items) )
3365 {
3366 GtkTreeIter iter;
3367 gtk_list_store_append( model, &iter );
3368 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
3369 count++;
3370 }
3371 g_list_free( items );
3372 items = 0;
3373 EgeSelectOneAction* act1 = ege_select_one_action_new(
3374 tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction",
3375 _("Shape:"), (""), NULL, GTK_TREE_MODEL(model));
3376 g_object_set( act1, "short_label", _("Shape:"), NULL );
3377 ege_select_one_action_set_appearance( act1, "compact" );
3378 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.freehand", "shape", 0) );
3379 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(sp_freehand_change_shape), holder );
3380 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
3381 g_object_set_data( holder, "shape_action", act1 );
3382 }
3383 }
3385 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3386 {
3387 sp_add_spiro_toggle(mainActions, holder, false);
3388 sp_freehand_add_advanced_shape_options(mainActions, holder, false);
3389 }
3392 static void
3393 sp_pencil_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
3394 {
3395 GtkWidget *tbl = GTK_WIDGET(obj);
3397 GtkAdjustment *adj;
3399 // fixme: make settable
3400 gdouble tolerance = 4;
3402 adj = (GtkAdjustment*)gtk_object_get_data(obj, "tolerance");
3403 gtk_adjustment_set_value(adj, tolerance);
3404 gtk_adjustment_value_changed(adj);
3406 spinbutton_defocus(GTK_OBJECT(tbl));
3407 }
3409 static void
3410 sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl)
3411 {
3413 // quit if run by the attr_changed listener
3414 if (g_object_get_data( tbl, "freeze" )) {
3415 return;
3416 }
3417 // in turn, prevent listener from responding
3418 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3419 prefs_set_double_attribute("tools.freehand.pencil",
3420 "tolerance", adj->value);
3421 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3423 }
3427 static void
3428 sp_pencil_tb_tolerance_value_changed_external(Inkscape::XML::Node */*repr*/,
3429 const gchar */*key*/,
3430 const gchar */*oldval*/,
3431 const gchar */*newval*/,
3432 bool /*is_interactive*/,
3433 void * data)
3434 {
3435 GObject* tbl = G_OBJECT(data);
3436 if (g_object_get_data( tbl, "freeze" )) {
3437 return;
3438 }
3440 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3442 GtkAdjustment * adj = (GtkAdjustment*)g_object_get_data(tbl,
3443 "tolerance");
3445 double v = prefs_get_double_attribute("tools.freehand.pencil",
3446 "tolerance", adj->value);
3447 gtk_adjustment_set_value(adj, v);
3448 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3450 }
3452 static Inkscape::XML::NodeEventVector pencil_node_events =
3453 {
3454 NULL,
3455 NULL,
3456 sp_pencil_tb_tolerance_value_changed_external,
3457 NULL,
3458 NULL,
3459 };
3462 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3463 {
3464 sp_add_spiro_toggle(mainActions, holder, true);
3466 EgeAdjustmentAction* eact = 0;
3468 /* Tolerance */
3469 {
3470 gchar const* labels[] = {_("(many nodes, rough)"), ("(default)"), 0, 0, 0, 0, ("(few nodes, smooth)")};
3471 gdouble values[] = {1, 10, 20, 30, 50, 75, 100};
3472 eact = create_adjustment_action( "PencilToleranceAction",
3473 _("Smoothing:"), _("Smoothing"),
3474 _("How much smoothing (simplifying) is applied to the line"),
3475 "tools.freehand.pencil", "tolerance",
3476 3.0,
3477 GTK_WIDGET(desktop->canvas), NULL,
3478 holder, TRUE, "altx-pencil",
3479 1, 100.0, 0.5, 0,
3480 labels, values, G_N_ELEMENTS(labels),
3481 sp_pencil_tb_tolerance_value_changed,
3482 1, 2);
3483 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3484 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3486 Inkscape::XML::Node *repr = inkscape_get_repr(INKSCAPE,
3487 "tools.freehand.pencil");
3488 repr->addListener(&pencil_node_events, G_OBJECT(holder));
3489 g_object_set_data(G_OBJECT(holder), "repr", repr);
3491 }
3493 /* advanced shape options */
3494 sp_freehand_add_advanced_shape_options(mainActions, holder, true);
3496 /* Reset */
3497 {
3498 InkAction* inky = ink_action_new( "PencilResetAction",
3499 _("Defaults"),
3500 _("Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
3501 GTK_STOCK_CLEAR,
3502 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3503 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder );
3504 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3505 }
3507 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3509 }
3512 //########################
3513 //## Tweak ##
3514 //########################
3516 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3517 {
3518 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
3519 }
3521 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3522 {
3523 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
3524 }
3526 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3527 {
3528 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3529 }
3531 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
3532 {
3533 int mode = ege_select_one_action_get_active( act );
3534 prefs_set_int_attribute("tools.tweak", "mode", mode);
3536 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
3537 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
3538 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
3539 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
3540 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
3541 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
3542 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
3543 if (doh) gtk_action_set_sensitive (doh, TRUE);
3544 if (dos) gtk_action_set_sensitive (dos, TRUE);
3545 if (dol) gtk_action_set_sensitive (dol, TRUE);
3546 if (doo) gtk_action_set_sensitive (doo, TRUE);
3547 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
3548 if (fid) gtk_action_set_sensitive (fid, FALSE);
3549 } else {
3550 if (doh) gtk_action_set_sensitive (doh, FALSE);
3551 if (dos) gtk_action_set_sensitive (dos, FALSE);
3552 if (dol) gtk_action_set_sensitive (dol, FALSE);
3553 if (doo) gtk_action_set_sensitive (doo, FALSE);
3554 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
3555 if (fid) gtk_action_set_sensitive (fid, TRUE);
3556 }
3557 }
3559 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3560 {
3561 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
3562 }
3564 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
3565 bool show = gtk_toggle_action_get_active( act );
3566 prefs_set_int_attribute ("tools.tweak", "doh", show ? 1 : 0);
3567 }
3568 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
3569 bool show = gtk_toggle_action_get_active( act );
3570 prefs_set_int_attribute ("tools.tweak", "dos", show ? 1 : 0);
3571 }
3572 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
3573 bool show = gtk_toggle_action_get_active( act );
3574 prefs_set_int_attribute ("tools.tweak", "dol", show ? 1 : 0);
3575 }
3576 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
3577 bool show = gtk_toggle_action_get_active( act );
3578 prefs_set_int_attribute ("tools.tweak", "doo", show ? 1 : 0);
3579 }
3581 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3582 {
3583 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
3585 {
3586 /* Width */
3587 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
3588 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3589 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
3590 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
3591 "tools.tweak", "width", 15,
3592 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
3593 1, 100, 1.0, 0.0,
3594 labels, values, G_N_ELEMENTS(labels),
3595 sp_tweak_width_value_changed, 0.01, 0, 100 );
3596 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3597 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3598 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3599 }
3602 {
3603 /* Force */
3604 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
3605 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
3606 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
3607 _("Force"), _("Force:"), _("The force of the tweak action"),
3608 "tools.tweak", "force", 20,
3609 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
3610 1, 100, 1.0, 0.0,
3611 labels, values, G_N_ELEMENTS(labels),
3612 sp_tweak_force_value_changed, 0.01, 0, 100 );
3613 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3614 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3615 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3616 }
3618 /* Mode */
3619 {
3620 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3622 GtkTreeIter iter;
3623 gtk_list_store_append( model, &iter );
3624 gtk_list_store_set( model, &iter,
3625 0, _("Push mode"),
3626 1, _("Push parts of paths in any direction"),
3627 2, "tweak_push_mode",
3628 -1 );
3630 gtk_list_store_append( model, &iter );
3631 gtk_list_store_set( model, &iter,
3632 0, _("Shrink mode"),
3633 1, _("Shrink (inset) parts of paths"),
3634 2, "tweak_shrink_mode",
3635 -1 );
3637 gtk_list_store_append( model, &iter );
3638 gtk_list_store_set( model, &iter,
3639 0, _("Grow mode"),
3640 1, _("Grow (outset) parts of paths"),
3641 2, "tweak_grow_mode",
3642 -1 );
3644 gtk_list_store_append( model, &iter );
3645 gtk_list_store_set( model, &iter,
3646 0, _("Attract mode"),
3647 1, _("Attract parts of paths towards cursor"),
3648 2, "tweak_attract_mode",
3649 -1 );
3651 gtk_list_store_append( model, &iter );
3652 gtk_list_store_set( model, &iter,
3653 0, _("Repel mode"),
3654 1, _("Repel parts of paths from cursor"),
3655 2, "tweak_repel_mode",
3656 -1 );
3658 gtk_list_store_append( model, &iter );
3659 gtk_list_store_set( model, &iter,
3660 0, _("Roughen mode"),
3661 1, _("Roughen parts of paths"),
3662 2, "tweak_roughen_mode",
3663 -1 );
3665 gtk_list_store_append( model, &iter );
3666 gtk_list_store_set( model, &iter,
3667 0, _("Color paint mode"),
3668 1, _("Paint the tool's color upon selected objects"),
3669 2, "tweak_colorpaint_mode",
3670 -1 );
3672 gtk_list_store_append( model, &iter );
3673 gtk_list_store_set( model, &iter,
3674 0, _("Color jitter mode"),
3675 1, _("Jitter the colors of selected objects"),
3676 2, "tweak_colorjitter_mode",
3677 -1 );
3679 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
3680 g_object_set( act, "short_label", _("Mode:"), NULL );
3681 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3682 g_object_set_data( holder, "mode_action", act );
3684 ege_select_one_action_set_appearance( act, "full" );
3685 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3686 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3687 ege_select_one_action_set_icon_column( act, 2 );
3688 ege_select_one_action_set_icon_size( act, secondarySize );
3689 ege_select_one_action_set_tooltip_column( act, 1 );
3691 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3692 ege_select_one_action_set_active( act, mode );
3693 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3695 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3696 }
3698 guint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3700 {
3701 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3702 ege_output_action_set_use_markup( act, TRUE );
3703 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3704 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3705 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3706 g_object_set_data( holder, "tweak_channels_label", act);
3707 }
3709 {
3710 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3711 _("Hue"),
3712 _("In color mode, act on objects' hue"),
3713 NULL,
3714 Inkscape::ICON_SIZE_DECORATION );
3715 //TRANSLATORS: "H" here stands for hue
3716 g_object_set( act, "short_label", _("H"), NULL );
3717 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3718 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3719 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doh", 1 ) );
3720 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3721 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3722 g_object_set_data( holder, "tweak_doh", act);
3723 }
3724 {
3725 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3726 _("Saturation"),
3727 _("In color mode, act on objects' saturation"),
3728 NULL,
3729 Inkscape::ICON_SIZE_DECORATION );
3730 //TRANSLATORS: "S" here stands for Saturation
3731 g_object_set( act, "short_label", _("S"), NULL );
3732 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3733 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3734 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dos", 1 ) );
3735 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3736 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3737 g_object_set_data( holder, "tweak_dos", act );
3738 }
3739 {
3740 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3741 _("Lightness"),
3742 _("In color mode, act on objects' lightness"),
3743 NULL,
3744 Inkscape::ICON_SIZE_DECORATION );
3745 //TRANSLATORS: "L" here stands for Lightness
3746 g_object_set( act, "short_label", _("L"), NULL );
3747 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3748 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3749 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dol", 1 ) );
3750 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3751 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3752 g_object_set_data( holder, "tweak_dol", act );
3753 }
3754 {
3755 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3756 _("Opacity"),
3757 _("In color mode, act on objects' opacity"),
3758 NULL,
3759 Inkscape::ICON_SIZE_DECORATION );
3760 //TRANSLATORS: "O" here stands for Opacity
3761 g_object_set( act, "short_label", _("O"), NULL );
3762 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3763 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3764 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doo", 1 ) );
3765 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3766 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3767 g_object_set_data( holder, "tweak_doo", act );
3768 }
3770 { /* Fidelity */
3771 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3772 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3773 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3774 _("Fidelity"), _("Fidelity:"),
3775 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3776 "tools.tweak", "fidelity", 50,
3777 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3778 1, 100, 1.0, 10.0,
3779 labels, values, G_N_ELEMENTS(labels),
3780 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3781 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3782 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3783 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3784 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3785 g_object_set_data( holder, "tweak_fidelity", eact );
3786 }
3789 /* Use Pressure button */
3790 {
3791 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3792 _("Pressure"),
3793 _("Use the pressure of the input device to alter the force of tweak action"),
3794 "use_pressure",
3795 Inkscape::ICON_SIZE_DECORATION );
3796 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3797 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3798 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
3799 }
3801 }
3804 //########################
3805 //## Calligraphy ##
3806 //########################
3807 static void update_presets_list (GObject *tbl){
3809 if (g_object_get_data(tbl, "presets_blocked"))
3810 return;
3812 EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
3813 if (sel) {
3814 ege_select_one_action_set_active(sel, 0);
3815 }
3816 }
3818 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
3819 {
3820 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value * 0.01 );
3821 update_presets_list(tbl);
3822 }
3824 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
3825 {
3826 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value * 0.01 );
3827 update_presets_list(tbl);
3828 }
3830 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
3831 {
3832 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
3833 update_presets_list(tbl);
3834 }
3836 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
3837 {
3838 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
3839 update_presets_list(tbl);
3840 }
3842 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
3843 {
3844 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value * 0.01 );
3845 update_presets_list(tbl);
3846 }
3848 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
3849 {
3850 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value * 0.01);
3851 update_presets_list(tbl);
3852 }
3854 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
3855 {
3856 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value * 0.01 );
3857 update_presets_list(tbl);
3858 }
3860 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
3861 {
3862 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
3863 update_presets_list(tbl);
3864 }
3866 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, GObject* tbl )
3867 {
3868 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3869 update_presets_list(tbl);
3870 }
3872 static void sp_ddc_trace_background_changed( GtkToggleAction *act, GObject* tbl )
3873 {
3874 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
3875 update_presets_list(tbl);
3876 }
3878 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject* tbl )
3879 {
3880 GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle_action"));
3881 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3882 update_presets_list(tbl);
3883 if (calligraphy_angle )
3884 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
3885 }
3888 #define NUMBER_OF_PRESET_PARAMS 11
3889 static gchar * widget_names[NUMBER_OF_PRESET_PARAMS] = {
3890 "width",
3891 "mass",
3892 "wiggle",
3893 "angle",
3894 "thinning",
3895 "tremor",
3896 "flatness",
3897 "cap_rounding",
3898 "usepressure",
3899 "tracebackground",
3900 "usetilt"
3901 };
3904 static void sp_dcc_build_presets_list(GObject *tbl)
3905 {
3906 EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
3907 GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
3908 gtk_list_store_clear (model);
3910 {
3911 GtkTreeIter iter;
3912 gtk_list_store_append( model, &iter );
3913 gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 );
3914 }
3916 //TODO: switch back to prefs API
3917 Inkscape::XML::Node *repr = inkscape_get_repr(INKSCAPE, "tools.calligraphic.preset" );
3918 Inkscape::XML::Node *child_repr = sp_repr_children(repr);
3919 int ii=1;
3920 while (child_repr) {
3921 GtkTreeIter iter;
3922 char *preset_name = (char *) child_repr->attribute("name");
3923 gtk_list_store_append( model, &iter );
3924 gtk_list_store_set( model, &iter, 0, preset_name, 1, ++ii, -1 );
3925 child_repr = sp_repr_next(child_repr);
3926 }
3928 {
3929 GtkTreeIter iter;
3930 gtk_list_store_append( model, &iter );
3931 gtk_list_store_set( model, &iter, 0, _("Save..."), 1, ii, -1 );
3932 g_object_set_data(tbl, "save_presets_index", GINT_TO_POINTER(ii));
3933 }
3935 update_presets_list (tbl);
3936 }
3938 static void sp_dcc_save_profile (GtkWidget */*widget*/, GObject *tbl)
3939 {
3940 SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop" );
3941 if (! desktop) return;
3943 if (g_object_get_data(tbl, "presets_blocked"))
3944 return;
3946 Inkscape::UI::Dialogs::CalligraphicProfileDialog::show(desktop);
3947 if ( ! Inkscape::UI::Dialogs::CalligraphicProfileDialog::applied()) {
3948 // dialog cancelled
3949 update_presets_list (tbl);
3950 return;
3951 }
3952 Glib::ustring profile_name = Inkscape::UI::Dialogs::CalligraphicProfileDialog::getProfileName();
3954 if (!profile_name.c_str() || *profile_name.c_str() == 0) {
3955 // empty name entered
3956 update_presets_list (tbl);
3957 return;
3958 }
3960 int new_index = -1;
3961 gchar *pref_path = NULL;
3962 int total_prefs = pref_path_number_of_children("tools.calligraphic.preset");
3964 for (int i = 1; i <= total_prefs; i++) {
3965 gchar *path = get_pref_nth_child("tools.calligraphic.preset", i);
3966 const gchar *name = prefs_get_string_attribute(path, "name");
3967 if (name && !strcmp(name, profile_name.c_str())) {
3968 // we already have preset with this name, replace its values
3969 new_index = i;
3970 pref_path = g_strdup(path);
3971 break;
3972 }
3973 }
3975 if (new_index == -1) {
3976 // no preset with this name, create
3977 new_index = total_prefs + 1;
3978 gchar *profile_id = g_strdup_printf("dcc%d", new_index);
3979 pref_path = create_pref("tools.calligraphic.preset", profile_id);
3980 free(profile_id);
3981 }
3983 for (unsigned i = 0; i < NUMBER_OF_PRESET_PARAMS; ++i) {
3984 gchar *widget_name = widget_names[i];
3985 void *widget = g_object_get_data(tbl, widget_name);
3986 if (widget) {
3987 if (GTK_IS_ADJUSTMENT(widget)) {
3988 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
3989 double v = gtk_adjustment_get_value(adj);
3990 prefs_set_double_attribute(pref_path, widget_name, v);
3991 //std::cout << "wrote adj " << widget_name << ": " << v << "\n";
3992 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
3993 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
3994 int v = gtk_toggle_action_get_active(toggle);
3995 prefs_set_int_attribute(pref_path, widget_name, v);
3996 //std::cout << "wrote tog " << widget_name << ": " << v << "\n";
3997 } else {
3998 g_warning("Unknown widget type for preset: %s\n", widget_name);
3999 }
4000 } else {
4001 g_warning("Bad key when writing preset: %s\n", widget_name);
4002 }
4003 }
4004 prefs_set_string_attribute(pref_path, "name", profile_name.c_str());
4006 sp_dcc_build_presets_list (tbl);
4008 free (pref_path);
4009 }
4012 static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject* tbl) {
4014 gint preset_index = ege_select_one_action_get_active( act );
4015 gint save_presets_index = GPOINTER_TO_INT(g_object_get_data(tbl, "save_presets_index"));
4017 if (preset_index == save_presets_index) {
4018 // this is the Save command
4019 sp_dcc_save_profile(NULL, tbl);
4020 return;
4021 }
4023 gchar *preset_path = get_pref_nth_child("tools.calligraphic.preset", preset_index);
4025 if (preset_path) {
4026 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE)); //temporarily block the selector so no one will updadte it while we're reading it
4028 Inkscape::XML::Node *preset_repr = inkscape_get_repr(INKSCAPE, preset_path);
4030 for ( Inkscape::Util::List<Inkscape::XML::AttributeRecord const> iter = preset_repr->attributeList();
4031 iter;
4032 ++iter ) {
4033 const gchar *attr_name = g_quark_to_string(iter->key);
4034 if (!strcmp(attr_name, "id") || !strcmp(attr_name, "name"))
4035 continue;
4036 void *widget = g_object_get_data(tbl, attr_name);
4037 if (widget) {
4038 if (GTK_IS_ADJUSTMENT(widget)) {
4039 double v = prefs_get_double_attribute(preset_path, attr_name, 0); // fixme: no min/max checks here, add?
4040 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
4041 gtk_adjustment_set_value(adj, v);
4042 //std::cout << "set adj " << attr_name << " to " << v << "\n";
4043 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
4044 int v = prefs_get_int_attribute(preset_path, attr_name, 0); // fixme: no min/max checks here, add?
4045 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
4046 gtk_toggle_action_set_active(toggle, v);
4047 //std::cout << "set toggle " << attr_name << " to " << v << "\n";
4048 } else {
4049 g_warning("Unknown widget type for preset: %s\n", attr_name);
4050 }
4051 } else {
4052 g_warning("Bad key found in a preset record: %s\n", attr_name);
4053 }
4054 }
4055 free(preset_path);
4056 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
4057 }
4059 }
4062 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4063 {
4064 {
4065 EgeAdjustmentAction* calligraphy_angle = 0;
4067 {
4068 /* Width */
4069 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
4070 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
4071 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
4072 _("Pen Width"), _("Width:"),
4073 _("The width of the calligraphic pen (relative to the visible canvas area)"),
4074 "tools.calligraphic", "width", 15,
4075 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
4076 1, 100, 1.0, 0.0,
4077 labels, values, G_N_ELEMENTS(labels),
4078 sp_ddc_width_value_changed, 0.01, 0, 100 );
4079 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4080 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4081 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4082 }
4084 {
4085 /* Thinning */
4086 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
4087 gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100};
4088 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
4089 _("Stroke Thinning"), _("Thinning:"),
4090 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
4091 "tools.calligraphic", "thinning", 10,
4092 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4093 -100, 100, 1, 0.1,
4094 labels, values, G_N_ELEMENTS(labels),
4095 sp_ddc_velthin_value_changed, 0.01, 0, 100);
4096 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4097 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4098 }
4100 {
4101 /* Angle */
4102 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
4103 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
4104 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
4105 _("Pen Angle"), _("Angle:"),
4106 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
4107 "tools.calligraphic", "angle", 30,
4108 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
4109 -90.0, 90.0, 1.0, 10.0,
4110 labels, values, G_N_ELEMENTS(labels),
4111 sp_ddc_angle_value_changed, 1, 0 );
4112 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4113 g_object_set_data( holder, "angle_action", eact );
4114 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4115 calligraphy_angle = eact;
4116 }
4118 {
4119 /* Fixation */
4120 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
4121 gdouble values[] = {0, 20, 40, 60, 90, 100};
4122 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
4123 _("Fixation"), _("Fixation:"),
4124 _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
4125 "tools.calligraphic", "flatness", 90,
4126 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4127 0.0, 100, 1.0, 10.0,
4128 labels, values, G_N_ELEMENTS(labels),
4129 sp_ddc_flatness_value_changed, 0.01, 0, 100 );
4130 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4131 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4132 }
4134 {
4135 /* Cap Rounding */
4136 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
4137 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
4138 // TRANSLATORS: "cap" means "end" (both start and finish) here
4139 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
4140 _("Cap rounding"), _("Caps:"),
4141 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
4142 "tools.calligraphic", "cap_rounding", 0.0,
4143 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4144 0.0, 5.0, 0.01, 0.1,
4145 labels, values, G_N_ELEMENTS(labels),
4146 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
4147 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4148 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4149 }
4151 {
4152 /* Tremor */
4153 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
4154 gdouble values[] = {0, 10, 20, 40, 60, 100};
4155 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
4156 _("Stroke Tremor"), _("Tremor:"),
4157 _("Increase to make strokes rugged and trembling"),
4158 "tools.calligraphic", "tremor", 0.0,
4159 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4160 0.0, 100, 1, 0.0,
4161 labels, values, G_N_ELEMENTS(labels),
4162 sp_ddc_tremor_value_changed, 0.01, 0, 100 );
4164 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4165 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4166 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4167 }
4169 {
4170 /* Wiggle */
4171 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
4172 gdouble values[] = {0, 20, 40, 60, 100};
4173 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
4174 _("Pen Wiggle"), _("Wiggle:"),
4175 _("Increase to make the pen waver and wiggle"),
4176 "tools.calligraphic", "wiggle", 0.0,
4177 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4178 0.0, 100, 1, 0.0,
4179 labels, values, G_N_ELEMENTS(labels),
4180 sp_ddc_wiggle_value_changed, 0.01, 0, 100 );
4181 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4182 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4183 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4184 }
4186 {
4187 /* Mass */
4188 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
4189 gdouble values[] = {0.0, 2, 10, 20, 50, 100};
4190 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
4191 _("Pen Mass"), _("Mass:"),
4192 _("Increase to make the pen drag behind, as if slowed by inertia"),
4193 "tools.calligraphic", "mass", 2.0,
4194 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4195 0.0, 100, 1, 0.0,
4196 labels, values, G_N_ELEMENTS(labels),
4197 sp_ddc_mass_value_changed, 0.01, 0, 100 );
4198 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4199 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4200 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4201 }
4204 /* Trace Background button */
4205 {
4206 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
4207 _("Trace Background"),
4208 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
4209 "trace_background",
4210 Inkscape::ICON_SIZE_DECORATION );
4211 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4212 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), holder);
4213 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
4214 g_object_set_data( holder, "tracebackground", act );
4215 }
4217 /* Use Pressure button */
4218 {
4219 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
4220 _("Pressure"),
4221 _("Use the pressure of the input device to alter the width of the pen"),
4222 "use_pressure",
4223 Inkscape::ICON_SIZE_DECORATION );
4224 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4225 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), holder);
4226 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
4227 g_object_set_data( holder, "usepressure", act );
4228 }
4230 /* Use Tilt button */
4231 {
4232 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
4233 _("Tilt"),
4234 _("Use the tilt of the input device to alter the angle of the pen's nib"),
4235 "use_tilt",
4236 Inkscape::ICON_SIZE_DECORATION );
4237 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4238 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), holder );
4239 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
4240 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
4241 g_object_set_data( holder, "usetilt", act );
4242 }
4244 /*calligraphic profile */
4245 {
4246 GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
4247 EgeSelectOneAction* act1 = ege_select_one_action_new ("SetProfileAction", "" , (_("Change calligraphic profile")), NULL, GTK_TREE_MODEL(model));
4248 ege_select_one_action_set_appearance (act1, "compact");
4249 g_object_set_data (holder, "profile_selector", act1 );
4251 sp_dcc_build_presets_list (holder);
4253 g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder);
4254 gtk_action_group_add_action(mainActions, GTK_ACTION(act1));
4255 }
4256 }
4257 }
4260 //########################
4261 //## Circle / Arc ##
4262 //########################
4264 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
4265 {
4266 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
4267 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
4269 if (v1 == 0 && v2 == 0) {
4270 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
4271 gtk_action_set_sensitive( ocb, FALSE );
4272 gtk_action_set_sensitive( make_whole, FALSE );
4273 }
4274 } else {
4275 gtk_action_set_sensitive( ocb, TRUE );
4276 gtk_action_set_sensitive( make_whole, TRUE );
4277 }
4278 }
4280 static void
4281 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
4282 {
4283 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4285 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
4286 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
4287 }
4289 // quit if run by the attr_changed listener
4290 if (g_object_get_data( tbl, "freeze" )) {
4291 return;
4292 }
4294 // in turn, prevent listener from responding
4295 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4297 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
4299 bool modmade = false;
4300 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
4301 items != NULL;
4302 items = items->next)
4303 {
4304 SPItem *item = SP_ITEM(items->data);
4306 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
4308 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
4309 SPArc *arc = SP_ARC(item);
4311 if (!strcmp(value_name, "start"))
4312 ge->start = (adj->value * M_PI)/ 180;
4313 else
4314 ge->end = (adj->value * M_PI)/ 180;
4316 sp_genericellipse_normalize(ge);
4317 ((SPObject *)arc)->updateRepr();
4318 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
4320 modmade = true;
4321 }
4322 }
4324 g_free(namespaced_name);
4326 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
4328 sp_arctb_sensitivize( tbl, adj->value, other->value );
4330 if (modmade) {
4331 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
4332 _("Arc: Change start/end"));
4333 }
4335 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4336 }
4339 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
4340 {
4341 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
4342 }
4344 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
4345 {
4346 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
4347 }
4350 static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
4351 {
4352 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4353 gint eraserMode = (ege_select_one_action_get_active( act ) != 0) ? 1 : 0;
4354 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
4355 prefs_set_int_attribute( "tools.eraser", "mode", eraserMode );
4356 }
4358 // only take action if run by the attr_changed listener
4359 if (!g_object_get_data( tbl, "freeze" )) {
4360 // in turn, prevent listener from responding
4361 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4363 if ( eraserMode != 0 ) {
4364 } else {
4365 }
4366 // TODO finish implementation
4368 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4369 }
4370 }
4372 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
4373 {
4374 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4375 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
4376 if ( ege_select_one_action_get_active( act ) != 0 ) {
4377 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
4378 } else {
4379 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
4380 }
4381 }
4383 // quit if run by the attr_changed listener
4384 if (g_object_get_data( tbl, "freeze" )) {
4385 return;
4386 }
4388 // in turn, prevent listener from responding
4389 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4391 bool modmade = false;
4393 if ( ege_select_one_action_get_active(act) != 0 ) {
4394 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
4395 items != NULL;
4396 items = items->next)
4397 {
4398 if (SP_IS_ARC((SPItem *) items->data)) {
4399 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
4400 repr->setAttribute("sodipodi:open", "true");
4401 SP_OBJECT((SPItem *) items->data)->updateRepr();
4402 modmade = true;
4403 }
4404 }
4405 } else {
4406 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
4407 items != NULL;
4408 items = items->next)
4409 {
4410 if (SP_IS_ARC((SPItem *) items->data)) {
4411 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
4412 repr->setAttribute("sodipodi:open", NULL);
4413 SP_OBJECT((SPItem *) items->data)->updateRepr();
4414 modmade = true;
4415 }
4416 }
4417 }
4419 if (modmade) {
4420 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
4421 _("Arc: Change open/closed"));
4422 }
4424 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4425 }
4427 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
4428 {
4429 GtkAdjustment *adj;
4430 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
4431 gtk_adjustment_set_value(adj, 0.0);
4432 gtk_adjustment_value_changed(adj);
4434 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
4435 gtk_adjustment_set_value(adj, 0.0);
4436 gtk_adjustment_value_changed(adj);
4438 spinbutton_defocus( GTK_OBJECT(obj) );
4439 }
4441 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
4442 gchar const */*old_value*/, gchar const */*new_value*/,
4443 bool /*is_interactive*/, gpointer data)
4444 {
4445 GObject *tbl = G_OBJECT(data);
4447 // quit if run by the _changed callbacks
4448 if (g_object_get_data( tbl, "freeze" )) {
4449 return;
4450 }
4452 // in turn, prevent callbacks from responding
4453 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4455 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
4456 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
4458 GtkAdjustment *adj1,*adj2;
4459 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
4460 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
4461 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
4462 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
4464 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
4466 char const *openstr = NULL;
4467 openstr = repr->attribute("sodipodi:open");
4468 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
4470 if (openstr) {
4471 ege_select_one_action_set_active( ocb, 1 );
4472 } else {
4473 ege_select_one_action_set_active( ocb, 0 );
4474 }
4476 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4477 }
4479 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
4480 NULL, /* child_added */
4481 NULL, /* child_removed */
4482 arc_tb_event_attr_changed,
4483 NULL, /* content_changed */
4484 NULL /* order_changed */
4485 };
4488 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
4489 {
4490 int n_selected = 0;
4491 Inkscape::XML::Node *repr = NULL;
4493 purge_repr_listener( tbl, tbl );
4495 for (GSList const *items = selection->itemList();
4496 items != NULL;
4497 items = items->next)
4498 {
4499 if (SP_IS_ARC((SPItem *) items->data)) {
4500 n_selected++;
4501 repr = SP_OBJECT_REPR((SPItem *) items->data);
4502 }
4503 }
4505 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
4507 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
4508 if (n_selected == 0) {
4509 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
4510 } else if (n_selected == 1) {
4511 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
4512 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
4514 if (repr) {
4515 g_object_set_data( tbl, "repr", repr );
4516 Inkscape::GC::anchor(repr);
4517 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
4518 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
4519 }
4520 } else {
4521 // FIXME: implement averaging of all parameters for multiple selected
4522 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
4523 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
4524 sp_arctb_sensitivize( tbl, 1, 0 );
4525 }
4526 }
4529 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4530 {
4531 EgeAdjustmentAction* eact = 0;
4532 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
4535 {
4536 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
4537 ege_output_action_set_use_markup( act, TRUE );
4538 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4539 g_object_set_data( holder, "mode_action", act );
4540 }
4542 /* Start */
4543 {
4544 eact = create_adjustment_action( "ArcStartAction",
4545 _("Start"), _("Start:"),
4546 _("The angle (in degrees) from the horizontal to the arc's start point"),
4547 "tools.shapes.arc", "start", 0.0,
4548 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
4549 -360.0, 360.0, 1.0, 10.0,
4550 0, 0, 0,
4551 sp_arctb_start_value_changed);
4552 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4553 }
4555 /* End */
4556 {
4557 eact = create_adjustment_action( "ArcEndAction",
4558 _("End"), _("End:"),
4559 _("The angle (in degrees) from the horizontal to the arc's end point"),
4560 "tools.shapes.arc", "end", 0.0,
4561 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
4562 -360.0, 360.0, 1.0, 10.0,
4563 0, 0, 0,
4564 sp_arctb_end_value_changed);
4565 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4566 }
4568 /* Segments / Pie checkbox */
4569 {
4570 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
4572 GtkTreeIter iter;
4573 gtk_list_store_append( model, &iter );
4574 gtk_list_store_set( model, &iter,
4575 0, _("Closed arc"),
4576 1, _("Switch to segment (closed shape with two radii)"),
4577 2, "circle_closed_arc",
4578 -1 );
4580 gtk_list_store_append( model, &iter );
4581 gtk_list_store_set( model, &iter,
4582 0, _("Open Arc"),
4583 1, _("Switch to arc (unclosed shape)"),
4584 2, "circle_open_arc",
4585 -1 );
4587 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
4588 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
4589 g_object_set_data( holder, "open_action", act );
4591 ege_select_one_action_set_appearance( act, "full" );
4592 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
4593 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
4594 ege_select_one_action_set_icon_column( act, 2 );
4595 ege_select_one_action_set_icon_size( act, secondarySize );
4596 ege_select_one_action_set_tooltip_column( act, 1 );
4598 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
4599 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
4600 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
4601 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
4602 }
4604 /* Make Whole */
4605 {
4606 InkAction* inky = ink_action_new( "ArcResetAction",
4607 _("Make whole"),
4608 _("Make the shape a whole ellipse, not arc or segment"),
4609 "reset_circle",
4610 secondarySize );
4611 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
4612 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4613 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
4614 g_object_set_data( holder, "make_whole", inky );
4615 }
4617 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
4618 // sensitivize make whole and open checkbox
4619 {
4620 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
4621 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
4622 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
4623 }
4626 sigc::connection *connection = new sigc::connection(
4627 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
4628 );
4629 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
4630 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
4631 }
4636 // toggle button callbacks and updaters
4638 //########################
4639 //## Dropper ##
4640 //########################
4642 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
4643 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
4644 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
4645 if ( set_action ) {
4646 if ( gtk_toggle_action_get_active( act ) ) {
4647 gtk_action_set_sensitive( set_action, TRUE );
4648 } else {
4649 gtk_action_set_sensitive( set_action, FALSE );
4650 }
4651 }
4653 spinbutton_defocus(GTK_OBJECT(tbl));
4654 }
4656 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
4657 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
4658 spinbutton_defocus(GTK_OBJECT(tbl));
4659 }
4662 /**
4663 * Dropper auxiliary toolbar construction and setup.
4664 *
4665 * TODO: Would like to add swatch of current color.
4666 * TODO: Add queue of last 5 or so colors selected with new swatches so that
4667 * can drag and drop places. Will provide a nice mixing palette.
4668 */
4669 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
4670 {
4671 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
4673 {
4674 EgeOutputAction* act = ege_output_action_new( "DropperOpacityAction", _("Opacity:"), "", 0 );
4675 ege_output_action_set_use_markup( act, TRUE );
4676 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4677 }
4679 {
4680 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
4681 _("Pick opacity"),
4682 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
4683 NULL,
4684 Inkscape::ICON_SIZE_DECORATION );
4685 g_object_set( act, "short_label", _("Pick"), NULL );
4686 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4687 g_object_set_data( holder, "pick_action", act );
4688 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
4689 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
4690 }
4692 {
4693 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
4694 _("Assign opacity"),
4695 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
4696 NULL,
4697 Inkscape::ICON_SIZE_DECORATION );
4698 g_object_set( act, "short_label", _("Assign"), NULL );
4699 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4700 g_object_set_data( holder, "set_action", act );
4701 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
4702 // make sure it's disabled if we're not picking alpha
4703 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
4704 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
4705 }
4706 }
4710 static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4711 {
4712 {
4713 /* Width */
4714 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
4715 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
4716 EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction",
4717 _("Pen Width"), _("Width:"),
4718 _("The width of the eraser pen (relative to the visible canvas area)"),
4719 "tools.eraser", "width", 15,
4720 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser",
4721 1, 100, 1.0, 0.0,
4722 labels, values, G_N_ELEMENTS(labels),
4723 sp_ddc_width_value_changed, 0.01, 0, 100 );
4724 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4725 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4726 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4727 }
4729 {
4730 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
4732 GtkTreeIter iter;
4733 gtk_list_store_append( model, &iter );
4734 gtk_list_store_set( model, &iter,
4735 0, _("Delete"),
4736 1, _("Delete objects touched by the eraser"),
4737 2, "delete_object",
4738 -1 );
4740 gtk_list_store_append( model, &iter );
4741 gtk_list_store_set( model, &iter,
4742 0, _("Cut"),
4743 1, _("Cut out from objects"),
4744 2, "difference",
4745 -1 );
4747 EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
4748 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
4749 g_object_set_data( holder, "eraser_mode_action", act );
4751 ege_select_one_action_set_appearance( act, "full" );
4752 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
4753 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
4754 ege_select_one_action_set_icon_column( act, 2 );
4755 ege_select_one_action_set_tooltip_column( act, 1 );
4757 gint eraserMode = (prefs_get_int_attribute("tools.eraser", "mode", 0) != 0) ? 1 : 0;
4758 ege_select_one_action_set_active( act, eraserMode );
4759 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder );
4760 }
4762 }
4764 //########################
4765 //## Text Toolbox ##
4766 //########################
4767 /*
4768 static void
4769 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
4770 {
4771 //Call back for letter sizing spinbutton
4772 }
4774 static void
4775 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
4776 {
4777 //Call back for line height spinbutton
4778 }
4780 static void
4781 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
4782 {
4783 //Call back for horizontal kerning spinbutton
4784 }
4786 static void
4787 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
4788 {
4789 //Call back for vertical kerning spinbutton
4790 }
4792 static void
4793 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
4794 {
4795 //Call back for letter rotation spinbutton
4796 }*/
4798 namespace {
4800 bool popdown_visible = false;
4801 bool popdown_hasfocus = false;
4803 void
4804 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
4805 {
4806 SPStyle *query =
4807 sp_style_new (SP_ACTIVE_DOCUMENT);
4809 // int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4811 int result_family =
4812 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
4814 int result_style =
4815 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
4817 int result_numbers =
4818 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4820 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4822 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4823 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) {
4824 // there are no texts in selection, read from prefs
4826 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
4827 if (repr) {
4828 sp_style_read_from_repr (query, repr);
4829 if (g_object_get_data(tbl, "text_style_from_prefs")) {
4830 // do not reset the toolbar style from prefs if we already did it last time
4831 sp_style_unref(query);
4832 return;
4833 }
4834 g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(TRUE));
4835 } else {
4836 sp_style_unref(query);
4837 return;
4838 }
4839 } else {
4840 g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(FALSE));
4841 }
4843 if (query->text)
4844 {
4845 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
4846 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
4847 gtk_entry_set_text (GTK_ENTRY (entry), "");
4849 } else if (query->text->font_specification.value || query->text->font_family.value) {
4851 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
4853 // Get the font that corresponds
4854 Glib::ustring familyName;
4856 font_instance * font = font_factory::Default()->FaceFromStyle(query);
4857 if (font) {
4858 familyName = font_factory::Default()->GetUIFamilyString(font->descr);
4859 font->Unref();
4860 font = NULL;
4861 }
4863 gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
4865 Gtk::TreePath path;
4866 try {
4867 path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
4868 } catch (...) {
4869 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
4870 sp_style_unref(query);
4871 return;
4872 }
4874 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4875 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4877 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
4879 gtk_tree_selection_select_path (tselection, path.gobj());
4880 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4882 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
4883 }
4885 //Size
4886 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4887 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
4888 g_object_set_data (tbl, "size-block", gpointer(1));
4889 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
4890 g_object_set_data (tbl, "size-block", gpointer(0));
4891 free (str);
4893 //Anchor
4894 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
4895 {
4896 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
4897 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4898 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4899 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4900 }
4901 else
4902 {
4903 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
4904 {
4905 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
4906 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4907 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4908 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4909 }
4910 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
4911 {
4912 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
4913 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4914 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4915 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4916 }
4917 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
4918 {
4919 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
4920 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4921 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4922 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4923 }
4924 }
4926 //Style
4927 {
4928 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
4930 gboolean active = gtk_toggle_button_get_active (button);
4931 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
4933 if (active != check)
4934 {
4935 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4936 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4937 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4938 }
4939 }
4941 {
4942 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
4944 gboolean active = gtk_toggle_button_get_active (button);
4945 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
4947 if (active != check)
4948 {
4949 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4950 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4951 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4952 }
4953 }
4955 //Orientation
4956 //locking both buttons, changing one affect all group (both)
4957 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
4958 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4960 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
4961 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
4963 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
4964 {
4965 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4966 }
4967 else
4968 {
4969 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
4970 }
4971 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4972 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
4973 }
4975 sp_style_unref(query);
4976 }
4978 void
4979 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
4980 {
4981 sp_text_toolbox_selection_changed (selection, tbl);
4982 }
4984 void
4985 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4986 {
4987 sp_text_toolbox_selection_changed (NULL, tbl);
4988 }
4990 void
4991 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4992 GObject *tbl)
4993 {
4994 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4995 GtkTreeModel *model = 0;
4996 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4997 GtkTreeIter iter;
4998 char *family = 0;
5000 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5001 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5003 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
5004 return;
5005 }
5007 gtk_tree_model_get (model, &iter, 0, &family, -1);
5009 if (g_object_get_data (G_OBJECT (selection), "block"))
5010 {
5011 gtk_entry_set_text (GTK_ENTRY (entry), family);
5012 return;
5013 }
5015 gtk_entry_set_text (GTK_ENTRY (entry), family);
5017 SPStyle *query =
5018 sp_style_new (SP_ACTIVE_DOCUMENT);
5020 int result_fontspec =
5021 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
5023 //font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
5025 SPCSSAttr *css = sp_repr_css_attr_new ();
5028 // First try to get the font spec from the stored value
5029 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
5031 if (fontSpec.empty()) {
5032 // Construct a new font specification if it does not yet exist
5033 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
5034 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
5035 fontFromStyle->Unref();
5036 }
5038 if (!fontSpec.empty()) {
5039 Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
5040 if (!newFontSpec.empty() && fontSpec != newFontSpec) {
5041 font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
5042 if (font) {
5043 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
5045 // Set all the these just in case they were altered when finding the best
5046 // match for the new family and old style...
5048 gchar c[256];
5050 font->Family(c, 256);
5051 sp_repr_css_set_property (css, "font-family", c);
5053 font->Attribute( "weight", c, 256);
5054 sp_repr_css_set_property (css, "font-weight", c);
5056 font->Attribute("style", c, 256);
5057 sp_repr_css_set_property (css, "font-style", c);
5059 font->Attribute("stretch", c, 256);
5060 sp_repr_css_set_property (css, "font-stretch", c);
5062 font->Attribute("variant", c, 256);
5063 sp_repr_css_set_property (css, "font-variant", c);
5065 font->Unref();
5066 }
5067 }
5068 }
5070 // If querying returned nothing, set the default style of the tool (for new texts)
5071 if (result_fontspec == QUERY_STYLE_NOTHING)
5072 {
5073 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
5074 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
5075 }
5076 else
5077 {
5078 sp_desktop_set_style (desktop, css, true, true);
5079 }
5081 sp_style_unref(query);
5083 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5084 _("Text: Change font family"));
5085 sp_repr_css_attr_unref (css);
5086 free (family);
5087 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
5089 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5090 }
5092 void
5093 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
5094 GObject *tbl)
5095 {
5096 const char *family = gtk_entry_get_text (entry);
5098 try {
5099 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
5100 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
5101 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
5102 gtk_tree_selection_select_path (selection, path.gobj());
5103 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
5104 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
5105 } catch (...) {
5106 if (family && strlen (family))
5107 {
5108 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
5109 }
5110 }
5111 }
5113 void
5114 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
5115 gpointer data)
5116 {
5117 if (g_object_get_data (G_OBJECT (button), "block")) return;
5118 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
5119 int prop = GPOINTER_TO_INT(data);
5121 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5122 SPCSSAttr *css = sp_repr_css_attr_new ();
5124 switch (prop)
5125 {
5126 case 0:
5127 {
5128 sp_repr_css_set_property (css, "text-anchor", "start");
5129 sp_repr_css_set_property (css, "text-align", "start");
5130 break;
5131 }
5132 case 1:
5133 {
5134 sp_repr_css_set_property (css, "text-anchor", "middle");
5135 sp_repr_css_set_property (css, "text-align", "center");
5136 break;
5137 }
5139 case 2:
5140 {
5141 sp_repr_css_set_property (css, "text-anchor", "end");
5142 sp_repr_css_set_property (css, "text-align", "end");
5143 break;
5144 }
5146 case 3:
5147 {
5148 sp_repr_css_set_property (css, "text-anchor", "start");
5149 sp_repr_css_set_property (css, "text-align", "justify");
5150 break;
5151 }
5152 }
5154 SPStyle *query =
5155 sp_style_new (SP_ACTIVE_DOCUMENT);
5156 int result_numbers =
5157 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5159 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5160 if (result_numbers == QUERY_STYLE_NOTHING)
5161 {
5162 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
5163 }
5165 sp_style_unref(query);
5167 sp_desktop_set_style (desktop, css, true, true);
5168 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5169 _("Text: Change alignment"));
5170 sp_repr_css_attr_unref (css);
5172 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5173 }
5175 void
5176 sp_text_toolbox_style_toggled (GtkToggleButton *button,
5177 gpointer data)
5178 {
5179 if (g_object_get_data (G_OBJECT (button), "block")) return;
5181 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5182 SPCSSAttr *css = sp_repr_css_attr_new ();
5183 int prop = GPOINTER_TO_INT(data);
5184 bool active = gtk_toggle_button_get_active (button);
5186 SPStyle *query =
5187 sp_style_new (SP_ACTIVE_DOCUMENT);
5189 int result_fontspec =
5190 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
5192 //int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
5193 //int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
5194 //int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5196 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
5197 Glib::ustring newFontSpec = "";
5199 if (fontSpec.empty()) {
5200 // Construct a new font specification if it does not yet exist
5201 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
5202 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
5203 fontFromStyle->Unref();
5204 }
5206 switch (prop)
5207 {
5208 case 0:
5209 {
5210 if (!fontSpec.empty()) {
5211 newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
5212 }
5213 if (fontSpec != newFontSpec) {
5214 // Don't even set the bold if the font didn't exist on the system
5215 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
5216 }
5217 break;
5218 }
5220 case 1:
5221 {
5222 if (!fontSpec.empty()) {
5223 newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
5224 }
5225 if (fontSpec != newFontSpec) {
5226 // Don't even set the italic if the font didn't exist on the system
5227 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
5228 }
5229 break;
5230 }
5231 }
5233 if (!newFontSpec.empty()) {
5234 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
5235 }
5237 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5238 if (result_fontspec == QUERY_STYLE_NOTHING)
5239 {
5240 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
5241 }
5243 sp_style_unref(query);
5245 sp_desktop_set_style (desktop, css, true, true);
5246 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5247 _("Text: Change font style"));
5248 sp_repr_css_attr_unref (css);
5250 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5251 }
5253 void
5254 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
5255 gpointer data)
5256 {
5257 if (g_object_get_data (G_OBJECT (button), "block")) {
5258 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5259 return;
5260 }
5262 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5263 SPCSSAttr *css = sp_repr_css_attr_new ();
5264 int prop = GPOINTER_TO_INT(data);
5266 switch (prop)
5267 {
5268 case 0:
5269 {
5270 sp_repr_css_set_property (css, "writing-mode", "lr");
5271 break;
5272 }
5274 case 1:
5275 {
5276 sp_repr_css_set_property (css, "writing-mode", "tb");
5277 break;
5278 }
5279 }
5281 SPStyle *query =
5282 sp_style_new (SP_ACTIVE_DOCUMENT);
5283 int result_numbers =
5284 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5286 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5287 if (result_numbers == QUERY_STYLE_NOTHING)
5288 {
5289 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
5290 }
5292 sp_desktop_set_style (desktop, css, true, true);
5293 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5294 _("Text: Change orientation"));
5295 sp_repr_css_attr_unref (css);
5297 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5298 }
5300 gboolean
5301 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
5302 {
5303 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5304 if (!desktop) return FALSE;
5306 switch (get_group0_keyval (event)) {
5307 case GDK_Escape: // defocus
5308 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5309 sp_text_toolbox_selection_changed (NULL, tbl); // update
5310 return TRUE; // I consumed the event
5311 break;
5312 }
5313 return FALSE;
5314 }
5316 gboolean
5317 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
5318 {
5319 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5320 if (!desktop) return FALSE;
5322 switch (get_group0_keyval (event)) {
5323 case GDK_KP_Enter:
5324 case GDK_Return:
5325 case GDK_Escape: // defocus
5326 gtk_widget_hide (w);
5327 popdown_visible = false;
5328 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5329 return TRUE; // I consumed the event
5330 break;
5331 case GDK_w:
5332 case GDK_W:
5333 if (event->state & GDK_CONTROL_MASK) {
5334 gtk_widget_hide (w);
5335 popdown_visible = false;
5336 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5337 return TRUE; // I consumed the event
5338 }
5339 break;
5340 }
5341 return FALSE;
5342 }
5345 void
5346 sp_text_toolbox_size_changed (GtkComboBox *cbox,
5347 GObject *tbl)
5348 {
5349 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5351 if (g_object_get_data (tbl, "size-block")) return;
5353 // If this is not from selecting a size in the list (in which case get_active will give the
5354 // index of the selected item, otherwise -1) and not from user pressing Enter/Return, do not
5355 // process this event. This fixes GTK's stupid insistence on sending an activate change every
5356 // time any character gets typed or deleted, which made this control nearly unusable in 0.45.
5357 if (gtk_combo_box_get_active (cbox) < 0 && !g_object_get_data (tbl, "enter-pressed"))
5358 return;
5360 gchar *endptr;
5361 gdouble value = -1;
5362 char *text = gtk_combo_box_get_active_text (cbox);
5363 if (text) {
5364 value = g_strtod (text, &endptr);
5365 if (endptr == text) // conversion failed, non-numeric input
5366 value = -1;
5367 free (text);
5368 }
5369 if (value <= 0) {
5370 return; // could not parse value
5371 }
5373 SPCSSAttr *css = sp_repr_css_attr_new ();
5374 Inkscape::CSSOStringStream osfs;
5375 osfs << value;
5376 sp_repr_css_set_property (css, "font-size", osfs.str().c_str());
5378 SPStyle *query =
5379 sp_style_new (SP_ACTIVE_DOCUMENT);
5380 int result_numbers =
5381 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5383 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5384 if (result_numbers == QUERY_STYLE_NOTHING)
5385 {
5386 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
5387 }
5389 sp_style_unref(query);
5391 sp_desktop_set_style (desktop, css, true, true);
5392 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
5393 _("Text: Change font size"));
5394 sp_repr_css_attr_unref (css);
5396 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5397 }
5399 gboolean
5400 sp_text_toolbox_size_focusout (GtkWidget */*w*/, GdkEventFocus */*event*/, GObject *tbl)
5401 {
5402 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5403 if (!desktop) return FALSE;
5405 if (!g_object_get_data (tbl, "esc-pressed")) {
5406 g_object_set_data (tbl, "enter-pressed", gpointer(1));
5407 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
5408 sp_text_toolbox_size_changed (cbox, tbl);
5409 g_object_set_data (tbl, "enter-pressed", gpointer(0));
5410 }
5411 return FALSE; // I consumed the event
5412 }
5415 gboolean
5416 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
5417 {
5418 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5419 if (!desktop) return FALSE;
5421 switch (get_group0_keyval (event)) {
5422 case GDK_Escape: // defocus
5423 g_object_set_data (tbl, "esc-pressed", gpointer(1));
5424 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5425 g_object_set_data (tbl, "esc-pressed", gpointer(0));
5426 return TRUE; // I consumed the event
5427 break;
5428 case GDK_Return: // defocus
5429 case GDK_KP_Enter:
5430 g_object_set_data (tbl, "enter-pressed", gpointer(1));
5431 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
5432 sp_text_toolbox_size_changed (cbox, tbl);
5433 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5434 g_object_set_data (tbl, "enter-pressed", gpointer(0));
5435 return TRUE; // I consumed the event
5436 break;
5437 }
5438 return FALSE;
5439 }
5441 void
5442 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
5443 GObject *tbl)
5444 {
5445 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
5446 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
5447 int x, y;
5449 if (!popdown_visible)
5450 {
5451 gdk_window_get_origin (widget->window, &x, &y);
5452 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
5453 gtk_widget_show_all (popdown);
5454 //sp_transientize (popdown);
5456 gdk_pointer_grab (widget->window, TRUE,
5457 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
5458 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
5459 GDK_POINTER_MOTION_MASK),
5460 NULL, NULL, GDK_CURRENT_TIME);
5462 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
5464 popdown_visible = true;
5465 }
5466 else
5467 {
5468 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5469 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5470 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5471 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5472 gtk_widget_hide (popdown);
5473 popdown_visible = false;
5474 }
5475 }
5477 gboolean
5478 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
5479 GdkEventFocus */*event*/,
5480 GObject */*tbl*/)
5481 {
5482 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
5483 return FALSE;
5484 }
5486 gboolean
5487 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
5488 GdkEventFocus */*event*/,
5489 GObject */*tbl*/)
5490 {
5491 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5493 if (popdown_hasfocus) {
5494 gtk_widget_hide (popdown);
5495 popdown_hasfocus = false;
5496 popdown_visible = false;
5497 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5498 return TRUE;
5499 }
5500 return FALSE;
5501 }
5503 gboolean
5504 sp_text_toolbox_popdown_focus_in (GtkWidget */*popdown*/,
5505 GdkEventFocus */*event*/,
5506 GObject */*tbl*/)
5507 {
5508 popdown_hasfocus = true;
5509 return TRUE;
5510 }
5513 void
5514 cell_data_func (GtkTreeViewColumn */*column*/,
5515 GtkCellRenderer *cell,
5516 GtkTreeModel *tree_model,
5517 GtkTreeIter *iter,
5518 gpointer /*data*/)
5519 {
5520 char *family,
5521 *family_escaped,
5522 *sample_escaped;
5524 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
5526 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
5528 family_escaped = g_markup_escape_text (family, -1);
5529 sample_escaped = g_markup_escape_text (sample, -1);
5531 std::stringstream markup;
5532 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
5533 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
5535 free (family);
5536 free (family_escaped);
5537 free (sample_escaped);
5538 }
5540 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
5541 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
5542 if (completion) {
5543 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
5544 g_object_unref (completion);
5545 }
5546 }
5548 GtkWidget*
5549 sp_text_toolbox_new (SPDesktop *desktop)
5550 {
5551 GtkToolbar *tbl = GTK_TOOLBAR(gtk_toolbar_new());
5552 GtkIconSize secondarySize = static_cast<GtkIconSize>(prefToSize("toolbox", "secondary", 1));
5554 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
5555 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
5557 GtkTooltips *tt = gtk_tooltips_new();
5558 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
5560 ////////////Family
5561 //Window
5562 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5563 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
5565 //Entry
5566 GtkWidget *entry = gtk_entry_new ();
5567 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
5568 GtkEntryCompletion *completion = gtk_entry_completion_new ();
5569 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
5570 gtk_entry_completion_set_text_column (completion, 0);
5571 gtk_entry_completion_set_minimum_key_length (completion, 1);
5572 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
5573 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
5574 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
5575 gtk_toolbar_append_widget( tbl, entry, "", "" );
5576 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
5578 //Button
5579 GtkWidget *button = gtk_button_new ();
5580 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
5581 gtk_toolbar_append_widget( tbl, button, "", "");
5583 //Popdown
5584 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
5585 GtkWidget *treeview = gtk_tree_view_new ();
5587 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
5588 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
5589 gtk_tree_view_column_pack_start (column, cell, FALSE);
5590 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
5591 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
5592 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
5594 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
5595 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
5596 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
5598 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
5600 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
5601 gtk_container_add (GTK_CONTAINER (sw), treeview);
5603 gtk_container_add (GTK_CONTAINER (window), sw);
5604 gtk_widget_set_size_request (window, 300, 450);
5606 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
5607 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
5608 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
5610 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
5612 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
5613 g_signal_connect (G_OBJECT (window), "focus-in-event", G_CALLBACK (sp_text_toolbox_popdown_focus_in), tbl);
5614 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
5616 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
5617 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
5619 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
5620 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
5621 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
5622 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
5623 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
5625 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, secondarySize);
5626 GtkWidget *box = gtk_event_box_new ();
5627 gtk_container_add (GTK_CONTAINER (box), image);
5628 gtk_toolbar_append_widget( tbl, box, "", "");
5629 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
5630 GtkTooltips *tooltips = gtk_tooltips_new ();
5631 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
5632 gtk_widget_hide (GTK_WIDGET (box));
5633 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
5635 ////////////Size
5636 const char *sizes[] = {
5637 "4", "6", "8", "9", "10", "11", "12", "13", "14",
5638 "16", "18", "20", "22", "24", "28",
5639 "32", "36", "40", "48", "56", "64", "72", "144"
5640 };
5642 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
5643 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
5644 gtk_widget_set_size_request (cbox, 80, -1);
5645 gtk_toolbar_append_widget( tbl, cbox, "", "");
5646 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
5647 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
5648 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), tbl);
5649 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "focus-out-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_focusout), tbl);
5651 ////////////Text anchor
5652 GtkWidget *group = gtk_radio_button_new (NULL);
5653 GtkWidget *row = gtk_hbox_new (FALSE, 4);
5654 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
5656 // left
5657 GtkWidget *rbutton = group;
5658 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5659 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, secondarySize));
5660 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5662 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5663 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
5664 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
5665 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
5667 // center
5668 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5669 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5670 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, secondarySize));
5671 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5673 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5674 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
5675 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
5676 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
5678 // right
5679 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5680 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5681 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, secondarySize));
5682 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5684 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5685 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
5686 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
5687 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
5689 // fill
5690 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5691 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5692 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, secondarySize));
5693 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5695 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5696 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
5697 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
5698 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
5700 gtk_toolbar_append_widget( tbl, row, "", "");
5702 //spacer
5703 gtk_toolbar_append_widget( tbl, gtk_vseparator_new(), "", "" );
5705 ////////////Text style
5706 row = gtk_hbox_new (FALSE, 4);
5708 // bold
5709 rbutton = gtk_toggle_button_new ();
5710 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5711 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, secondarySize));
5712 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5713 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
5715 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5716 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
5717 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
5719 // italic
5720 rbutton = gtk_toggle_button_new ();
5721 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5722 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, secondarySize));
5723 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5724 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
5726 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5727 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
5728 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
5730 gtk_toolbar_append_widget( tbl, row, "", "");
5732 //spacer
5733 gtk_toolbar_append_widget( tbl, gtk_vseparator_new(), "", "" );
5735 ////////////Text orientation
5736 group = gtk_radio_button_new (NULL);
5737 row = gtk_hbox_new (FALSE, 4);
5738 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
5740 // horizontal
5741 rbutton = group;
5742 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5743 gtk_container_add (GTK_CONTAINER (rbutton),
5744 sp_icon_new (static_cast<Inkscape::IconSize>(secondarySize), INKSCAPE_STOCK_WRITING_MODE_LR));
5745 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5746 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
5748 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5749 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
5750 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
5752 // vertical
5753 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5754 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5755 gtk_container_add (GTK_CONTAINER (rbutton),
5756 sp_icon_new (static_cast<Inkscape::IconSize>(secondarySize), INKSCAPE_STOCK_WRITING_MODE_TB));
5757 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5758 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
5760 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5761 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
5762 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
5763 gtk_toolbar_append_widget( tbl, row, "", "" );
5766 //watch selection
5767 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
5769 sigc::connection *c_selection_changed =
5770 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
5771 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
5772 pool->add_connection ("selection-changed", c_selection_changed);
5774 sigc::connection *c_selection_modified =
5775 new sigc::connection (sp_desktop_selection (desktop)->connectModified
5776 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
5777 pool->add_connection ("selection-modified", c_selection_modified);
5779 sigc::connection *c_subselection_changed =
5780 new sigc::connection (desktop->connectToolSubselectionChanged
5781 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
5782 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
5784 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
5787 gtk_widget_show_all( GTK_WIDGET(tbl) );
5789 return GTK_WIDGET(tbl);
5790 } // end of sp_text_toolbox_new()
5792 }//<unnamed> namespace
5795 //#########################
5796 //## Connector ##
5797 //#########################
5799 static void sp_connector_path_set_avoid(void)
5800 {
5801 cc_selection_set_avoid(true);
5802 }
5805 static void sp_connector_path_set_ignore(void)
5806 {
5807 cc_selection_set_avoid(false);
5808 }
5812 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
5813 {
5814 // quit if run by the _changed callbacks
5815 if (g_object_get_data( tbl, "freeze" )) {
5816 return;
5817 }
5819 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
5820 SPDocument *doc = sp_desktop_document(desktop);
5822 if (!sp_document_get_undo_sensitive(doc))
5823 {
5824 return;
5825 }
5827 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5829 if ( repr->attribute("inkscape:connector-spacing") ) {
5830 gdouble priorValue = gtk_adjustment_get_value(adj);
5831 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
5832 if ( priorValue == gtk_adjustment_get_value(adj) ) {
5833 return;
5834 }
5835 } else if ( adj->value == defaultConnSpacing ) {
5836 return;
5837 }
5839 // in turn, prevent callbacks from responding
5840 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
5842 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
5843 SP_OBJECT(desktop->namedview)->updateRepr();
5845 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
5846 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
5847 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
5848 NR::Matrix m = NR::identity();
5849 avoid_item_move(&m, item);
5850 }
5852 if (items) {
5853 g_slist_free(items);
5854 }
5856 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
5857 _("Change connector spacing"));
5859 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5861 spinbutton_defocus(GTK_OBJECT(tbl));
5862 }
5864 static void sp_connector_graph_layout(void)
5865 {
5866 if (!SP_ACTIVE_DESKTOP) return;
5868 // hack for clones, see comment in align-and-distribute.cpp
5869 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
5870 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
5872 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
5874 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
5876 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
5877 }
5879 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
5880 {
5881 if ( gtk_toggle_action_get_active( act ) ) {
5882 prefs_set_string_attribute("tools.connector", "directedlayout",
5883 "true");
5884 } else {
5885 prefs_set_string_attribute("tools.connector", "directedlayout",
5886 "false");
5887 }
5888 }
5890 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
5891 {
5892 if ( gtk_toggle_action_get_active( act ) ) {
5893 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
5894 "true");
5895 } else {
5896 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
5897 "false");
5898 }
5899 }
5902 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
5903 {
5904 prefs_set_double_attribute("tools.connector", "length", adj->value);
5905 spinbutton_defocus(GTK_OBJECT(tbl));
5906 }
5908 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
5909 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
5910 bool /*is_interactive*/, gpointer data)
5911 {
5912 GtkWidget *tbl = GTK_WIDGET(data);
5914 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
5915 return;
5916 }
5917 if (strcmp(name, "inkscape:connector-spacing") != 0) {
5918 return;
5919 }
5921 GtkAdjustment *adj = (GtkAdjustment*)
5922 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
5923 gdouble spacing = defaultConnSpacing;
5924 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
5926 gtk_adjustment_set_value(adj, spacing);
5927 }
5930 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
5931 NULL, /* child_added */
5932 NULL, /* child_removed */
5933 connector_tb_event_attr_changed,
5934 NULL, /* content_changed */
5935 NULL /* order_changed */
5936 };
5939 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
5940 {
5941 Inkscape::IconSize secondarySize = prefToSize("toolbox", "secondary", 1);
5943 {
5944 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
5945 _("Avoid"),
5946 _("Make connectors avoid selected objects"),
5947 "connector_avoid",
5948 secondarySize );
5949 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
5950 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5951 }
5953 {
5954 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
5955 _("Ignore"),
5956 _("Make connectors ignore selected objects"),
5957 "connector_ignore",
5958 secondarySize );
5959 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
5960 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5961 }
5963 EgeAdjustmentAction* eact = 0;
5965 // Spacing spinbox
5966 eact = create_adjustment_action( "ConnectorSpacingAction",
5967 _("Connector Spacing"), _("Spacing:"),
5968 _("The amount of space left around objects by auto-routing connectors"),
5969 "tools.connector", "spacing", defaultConnSpacing,
5970 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
5971 0, 100, 1.0, 10.0,
5972 0, 0, 0,
5973 connector_spacing_changed, 1, 0 );
5974 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5976 // Graph (connector network) layout
5977 {
5978 InkAction* inky = ink_action_new( "ConnectorGraphAction",
5979 _("Graph"),
5980 _("Nicely arrange selected connector network"),
5981 "graph_layout",
5982 secondarySize );
5983 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
5984 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5985 }
5987 // Default connector length spinbox
5988 eact = create_adjustment_action( "ConnectorLengthAction",
5989 _("Connector Length"), _("Length:"),
5990 _("Ideal length for connectors when layout is applied"),
5991 "tools.connector", "length", 100,
5992 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
5993 10, 1000, 10.0, 100.0,
5994 0, 0, 0,
5995 connector_length_changed, 1, 0 );
5996 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5999 // Directed edges toggle button
6000 {
6001 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
6002 _("Downwards"),
6003 _("Make connectors with end-markers (arrows) point downwards"),
6004 "directed_graph",
6005 Inkscape::ICON_SIZE_DECORATION );
6006 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
6008 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
6009 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
6010 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
6012 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
6013 }
6015 // Avoid overlaps toggle button
6016 {
6017 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
6018 _("Remove overlaps"),
6019 _("Do not allow overlapping shapes"),
6020 "remove_overlaps",
6021 Inkscape::ICON_SIZE_DECORATION );
6022 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
6024 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
6025 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
6026 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
6028 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
6029 }
6031 // Code to watch for changes to the connector-spacing attribute in
6032 // the XML.
6033 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
6034 g_assert(repr != NULL);
6036 purge_repr_listener( holder, holder );
6038 if (repr) {
6039 g_object_set_data( holder, "repr", repr );
6040 Inkscape::GC::anchor(repr);
6041 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
6042 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
6043 }
6044 } // end of sp_connector_toolbox_prep()
6047 //#########################
6048 //## Paintbucket ##
6049 //#########################
6051 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
6052 {
6053 gint channels = ege_select_one_action_get_active( act );
6054 flood_channels_set_channels( channels );
6055 }
6057 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
6058 {
6059 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
6060 }
6062 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
6063 {
6064 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
6065 }
6067 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
6068 {
6069 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
6070 SPUnit const *unit = tracker->getActiveUnit();
6072 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
6074 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
6075 }
6077 static void paintbucket_defaults (GtkWidget *, GObject *tbl)
6078 {
6079 // FIXME: make defaults settable via Inkscape Options
6080 struct KeyValue {
6081 char const *key;
6082 double value;
6083 } const key_values[] = {
6084 {"threshold", 15},
6085 {"offset", 0.0}
6086 };
6088 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
6089 KeyValue const &kv = key_values[i];
6090 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(tbl, kv.key));
6091 if ( adj ) {
6092 gtk_adjustment_set_value(adj, kv.value);
6093 }
6094 }
6096 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "channels_action" ) );
6097 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
6098 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "autogap_action" ) );
6099 ege_select_one_action_set_active( autogap_action, 0 );
6100 }
6102 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
6103 {
6104 EgeAdjustmentAction* eact = 0;
6106 {
6107 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
6109 GList* items = 0;
6110 gint count = 0;
6111 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
6112 {
6113 GtkTreeIter iter;
6114 gtk_list_store_append( model, &iter );
6115 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
6116 count++;
6117 }
6118 g_list_free( items );
6119 items = 0;
6120 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
6121 g_object_set( act1, "short_label", _("Fill by:"), NULL );
6122 ege_select_one_action_set_appearance( act1, "compact" );
6123 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
6124 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
6125 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
6126 g_object_set_data( holder, "channels_action", act1 );
6127 }
6129 // Spacing spinbox
6130 {
6131 eact = create_adjustment_action(
6132 "ThresholdAction",
6133 _("Fill Threshold"), _("Threshold:"),
6134 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
6135 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
6136 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 0.0,
6137 0, 0, 0,
6138 paintbucket_threshold_changed, 1, 0 );
6140 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
6141 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
6142 }
6144 // Create the units menu.
6145 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
6146 const gchar *stored_unit = prefs_get_string_attribute("tools.paintbucket", "offsetunits");
6147 if (stored_unit)
6148 tracker->setActiveUnit(sp_unit_get_by_abbreviation(stored_unit));
6149 g_object_set_data( holder, "tracker", tracker );
6150 {
6151 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
6152 gtk_action_group_add_action( mainActions, act );
6153 }
6155 // Offset spinbox
6156 {
6157 eact = create_adjustment_action(
6158 "OffsetAction",
6159 _("Grow/shrink by"), _("Grow/shrink by:"),
6160 _("The amount to grow (positive) or shrink (negative) the created fill path"),
6161 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
6162 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
6163 0, 0, 0,
6164 paintbucket_offset_changed, 1, 2);
6165 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
6167 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
6168 }
6170 /* Auto Gap */
6171 {
6172 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
6174 GList* items = 0;
6175 gint count = 0;
6176 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
6177 {
6178 GtkTreeIter iter;
6179 gtk_list_store_append( model, &iter );
6180 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
6181 count++;
6182 }
6183 g_list_free( items );
6184 items = 0;
6185 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
6186 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
6187 ege_select_one_action_set_appearance( act2, "compact" );
6188 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
6189 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
6190 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
6191 g_object_set_data( holder, "autogap_action", act2 );
6192 }
6194 /* Reset */
6195 {
6196 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
6197 _("Defaults"),
6198 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
6199 GTK_STOCK_CLEAR );
6200 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
6201 gtk_action_group_add_action( mainActions, act );
6202 gtk_action_set_sensitive( act, TRUE );
6203 }
6205 }
6207 /*
6208 Local Variables:
6209 mode:c++
6210 c-file-style:"stroustrup"
6211 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
6212 indent-tabs-mode:nil
6213 fill-column:99
6214 End:
6215 */
6216 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :