ca6a72ca2ec6c929393caac18f4bc88f7d5834ac
1 /** @file
2 * @brief Controls bars for some of Inkscape's tools (for some tools,
3 * they are in their own files)
4 */
5 /* Authors:
6 * MenTaLguY <mental@rydia.net>
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * bulia byak <buliabyak@users.sf.net>
9 * Frank Felfe <innerspace@iname.com>
10 * John Cliff <simarilius@yahoo.com>
11 * David Turner <novalis@gnu.org>
12 * Josh Andler <scislac@scislac.com>
13 * Jon A. Cruz <jon@joncruz.org>
14 * Maximilian Albert <maximilian.albert@gmail.com>
15 *
16 * Copyright (C) 2004 David Turner
17 * Copyright (C) 2003 MenTaLguY
18 * Copyright (C) 1999-2008 authors
19 * Copyright (C) 2001-2002 Ximian, Inc.
20 *
21 * Released under GNU GPL, read the file 'COPYING' for more information
22 */
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <cstring>
29 #include <string>
31 #include <gtkmm.h>
32 #include <gtk/gtk.h>
33 #include <iostream>
34 #include <sstream>
35 #include <glibmm/i18n.h>
37 #include "../box3d-context.h"
38 #include "../box3d.h"
39 #include "calligraphic-profile-rename.h"
40 #include "../conn-avoid-ref.h"
41 #include "../connection-pool.h"
42 #include "../connector-context.h"
43 #include "../desktop.h"
44 #include "../desktop-handles.h"
45 #include "../desktop-style.h"
46 #include "../dialogs/dialog-events.h"
47 #include "../dialogs/text-edit.h"
48 #include "../document-private.h"
49 #include "../ege-adjustment-action.h"
50 #include "../ege-output-action.h"
51 #include "../ege-select-one-action.h"
52 #include "../flood-context.h"
53 #include "gradient-toolbar.h"
54 #include "../graphlayout/graphlayout.h"
55 #include "../helper/unit-menu.h"
56 #include "../helper/units.h"
57 #include "../helper/unit-tracker.h"
58 #include "icon.h"
59 #include "../ink-action.h"
60 #include "../inkscape.h"
61 #include "../inkscape-stock.h"
62 #include "../interface.h"
63 #include "../libnrtype/font-instance.h"
64 #include "../libnrtype/font-lister.h"
65 #include "../live_effects/effect.h"
66 #include "../live_effects/lpe-angle_bisector.h"
67 #include "../live_effects/lpe-line_segment.h"
68 #include "../lpe-tool-context.h"
69 #include "../mod360.h"
70 #include "../node-context.h"
71 #include "../pen-context.h"
72 #include "../preferences.h"
73 #include "../selection-chemistry.h"
74 #include "../selection.h"
75 #include "select-toolbar.h"
76 #include "../shape-editor.h"
77 #include "../shortcuts.h"
78 #include "../sp-clippath.h"
79 #include "../sp-ellipse.h"
80 #include "../sp-flowtext.h"
81 #include "../sp-mask.h"
82 #include "../sp-namedview.h"
83 #include "../sp-rect.h"
84 #include "../sp-spiral.h"
85 #include "../sp-star.h"
86 #include "../sp-text.h"
87 #include "../style.h"
88 #include "../svg/css-ostringstream.h"
89 #include "../tools-switch.h"
90 #include "../tweak-context.h"
91 #include "../ui/widget/style-swatch.h"
92 #include "../verbs.h"
93 #include "../widgets/button.h"
94 #include "../widgets/spinbutton-events.h"
95 #include "../widgets/spw-utilities.h"
96 #include "../widgets/widget-sizes.h"
97 #include "../xml/attribute-record.h"
98 #include "../xml/node-event-vector.h"
99 #include "../xml/repr.h"
101 #include "toolbox.h"
103 using Inkscape::UnitTracker;
105 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
106 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
108 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
118 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
120 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
121 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
122 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
123 static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
124 static void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
126 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
129 Inkscape::IconSize prefToSize( Glib::ustring const &path, int base ) {
130 static Inkscape::IconSize sizeChoices[] = {
131 Inkscape::ICON_SIZE_LARGE_TOOLBAR,
132 Inkscape::ICON_SIZE_SMALL_TOOLBAR,
133 Inkscape::ICON_SIZE_MENU
134 };
135 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
136 int index = prefs->getIntLimited( path, base, 0, G_N_ELEMENTS(sizeChoices) );
137 return sizeChoices[index];
138 }
140 static struct {
141 gchar const *type_name;
142 gchar const *data_name;
143 sp_verb_t verb;
144 sp_verb_t doubleclick_verb;
145 } const tools[] = {
146 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
147 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
148 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
149 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
150 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
151 { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
152 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
153 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
154 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
155 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
156 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
157 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
158 { "SPLPEToolContext", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS },
159 { "SPEraserContext", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS },
160 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
161 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
162 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
163 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
164 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
165 { NULL, NULL, 0, 0 }
166 };
168 static struct {
169 gchar const *type_name;
170 gchar const *data_name;
171 GtkWidget *(*create_func)(SPDesktop *desktop);
172 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
173 gchar const *ui_name;
174 gint swatch_verb_id;
175 gchar const *swatch_tool;
176 gchar const *swatch_tip;
177 } const aux_toolboxes[] = {
178 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
179 SP_VERB_INVALID, 0, 0},
180 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
181 SP_VERB_INVALID, 0, 0},
182 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
183 SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")},
184 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
185 SP_VERB_INVALID, 0, 0},
186 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
187 SP_VERB_CONTEXT_STAR_PREFS, "/tools/shapes/star", N_("Style of new stars")},
188 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
189 SP_VERB_CONTEXT_RECT_PREFS, "/tools/shapes/rect", N_("Style of new rectangles")},
190 { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar",
191 SP_VERB_CONTEXT_3DBOX_PREFS, "/tools/shapes/3dbox", N_("Style of new 3D boxes")},
192 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
193 SP_VERB_CONTEXT_ARC_PREFS, "/tools/shapes/arc", N_("Style of new ellipses")},
194 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
195 SP_VERB_CONTEXT_SPIRAL_PREFS, "/tools/shapes/spiral", N_("Style of new spirals")},
196 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
197 SP_VERB_CONTEXT_PENCIL_PREFS, "/tools/freehand/pencil", N_("Style of new paths created by Pencil")},
198 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
199 SP_VERB_CONTEXT_PEN_PREFS, "/tools/freehand/pen", N_("Style of new paths created by Pen")},
200 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
201 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "/tools/calligraphic", N_("Style of new calligraphic strokes")},
202 { "SPEraserContext", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar",
203 SP_VERB_CONTEXT_ERASER_PREFS, "/tools/eraser", _("TBD")},
204 { "SPLPEToolContext", "lpetool_toolbox", 0, sp_lpetool_toolbox_prep, "LPEToolToolbar",
205 SP_VERB_CONTEXT_LPETOOL_PREFS, "/tools/lpetool", _("TBD")},
206 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
207 SP_VERB_INVALID, 0, 0},
208 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
209 SP_VERB_INVALID, 0, 0},
210 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
211 SP_VERB_INVALID, 0, 0},
212 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
213 SP_VERB_INVALID, 0, 0},
214 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
215 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")},
216 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
217 };
219 #define TOOLBAR_SLIDER_HINT "full"
221 static gchar const * ui_descr =
222 "<ui>"
223 " <toolbar name='SelectToolbar'>"
224 " <toolitem action='EditSelectAll' />"
225 " <toolitem action='EditSelectAllInAllLayers' />"
226 " <toolitem action='EditDeselect' />"
227 " <separator />"
228 " <toolitem action='ObjectRotate90CCW' />"
229 " <toolitem action='ObjectRotate90' />"
230 " <toolitem action='ObjectFlipHorizontally' />"
231 " <toolitem action='ObjectFlipVertically' />"
232 " <separator />"
233 " <toolitem action='SelectionToBack' />"
234 " <toolitem action='SelectionLower' />"
235 " <toolitem action='SelectionRaise' />"
236 " <toolitem action='SelectionToFront' />"
237 " <separator />"
238 " <toolitem action='XAction' />"
239 " <toolitem action='YAction' />"
240 " <toolitem action='WidthAction' />"
241 " <toolitem action='LockAction' />"
242 " <toolitem action='HeightAction' />"
243 " <toolitem action='UnitsAction' />"
244 " <separator />"
245 " <toolitem action='transform_affect_label' />"
246 " <toolitem action='transform_stroke' />"
247 " <toolitem action='transform_corners' />"
248 " <toolitem action='transform_gradient' />"
249 " <toolitem action='transform_pattern' />"
250 " </toolbar>"
252 " <toolbar name='NodeToolbar'>"
253 " <toolitem action='NodeInsertAction' />"
254 " <toolitem action='NodeDeleteAction' />"
255 " <separator />"
256 " <toolitem action='NodeJoinAction' />"
257 " <toolitem action='NodeBreakAction' />"
258 " <separator />"
259 " <toolitem action='NodeJoinSegmentAction' />"
260 " <toolitem action='NodeDeleteSegmentAction' />"
261 " <separator />"
262 " <toolitem action='NodeCuspAction' />"
263 " <toolitem action='NodeSmoothAction' />"
264 " <toolitem action='NodeSymmetricAction' />"
265 " <toolitem action='NodeAutoAction' />"
266 " <separator />"
267 " <toolitem action='NodeLineAction' />"
268 " <toolitem action='NodeCurveAction' />"
269 " <separator />"
270 " <toolitem action='ObjectToPath' />"
271 " <toolitem action='StrokeToPath' />"
272 " <separator />"
273 " <toolitem action='NodeXAction' />"
274 " <toolitem action='NodeYAction' />"
275 " <toolitem action='NodeUnitsAction' />"
276 " <separator />"
277 " <toolitem action='ObjectEditClipPathAction' />"
278 " <toolitem action='ObjectEditMaskPathAction' />"
279 " <toolitem action='EditNextLPEParameterAction' />"
280 " <separator />"
281 " <toolitem action='NodesShowHandlesAction' />"
282 " <toolitem action='NodesShowHelperpath' />"
283 " </toolbar>"
285 " <toolbar name='TweakToolbar'>"
286 " <toolitem action='TweakWidthAction' />"
287 " <separator />"
288 " <toolitem action='TweakForceAction' />"
289 " <toolitem action='TweakPressureAction' />"
290 " <separator />"
291 " <toolitem action='TweakModeAction' />"
292 " <separator />"
293 " <toolitem action='TweakFidelityAction' />"
294 " <separator />"
295 " <toolitem action='TweakChannelsLabel' />"
296 " <toolitem action='TweakDoH' />"
297 " <toolitem action='TweakDoS' />"
298 " <toolitem action='TweakDoL' />"
299 " <toolitem action='TweakDoO' />"
300 " </toolbar>"
302 " <toolbar name='ZoomToolbar'>"
303 " <toolitem action='ZoomIn' />"
304 " <toolitem action='ZoomOut' />"
305 " <separator />"
306 " <toolitem action='Zoom1:0' />"
307 " <toolitem action='Zoom1:2' />"
308 " <toolitem action='Zoom2:1' />"
309 " <separator />"
310 " <toolitem action='ZoomSelection' />"
311 " <toolitem action='ZoomDrawing' />"
312 " <toolitem action='ZoomPage' />"
313 " <toolitem action='ZoomPageWidth' />"
314 " <separator />"
315 " <toolitem action='ZoomPrev' />"
316 " <toolitem action='ZoomNext' />"
317 " </toolbar>"
319 " <toolbar name='StarToolbar'>"
320 " <separator />"
321 " <toolitem action='StarStateAction' />"
322 " <separator />"
323 " <toolitem action='FlatAction' />"
324 " <separator />"
325 " <toolitem action='MagnitudeAction' />"
326 " <toolitem action='SpokeAction' />"
327 " <toolitem action='RoundednessAction' />"
328 " <toolitem action='RandomizationAction' />"
329 " <separator />"
330 " <toolitem action='StarResetAction' />"
331 " </toolbar>"
333 " <toolbar name='RectToolbar'>"
334 " <toolitem action='RectStateAction' />"
335 " <toolitem action='RectWidthAction' />"
336 " <toolitem action='RectHeightAction' />"
337 " <toolitem action='RadiusXAction' />"
338 " <toolitem action='RadiusYAction' />"
339 " <toolitem action='RectUnitsAction' />"
340 " <separator />"
341 " <toolitem action='RectResetAction' />"
342 " </toolbar>"
344 " <toolbar name='3DBoxToolbar'>"
345 " <toolitem action='3DBoxAngleXAction' />"
346 " <toolitem action='3DBoxVPXStateAction' />"
347 " <separator />"
348 " <toolitem action='3DBoxAngleYAction' />"
349 " <toolitem action='3DBoxVPYStateAction' />"
350 " <separator />"
351 " <toolitem action='3DBoxAngleZAction' />"
352 " <toolitem action='3DBoxVPZStateAction' />"
353 " </toolbar>"
355 " <toolbar name='SpiralToolbar'>"
356 " <toolitem action='SpiralStateAction' />"
357 " <toolitem action='SpiralRevolutionAction' />"
358 " <toolitem action='SpiralExpansionAction' />"
359 " <toolitem action='SpiralT0Action' />"
360 " <separator />"
361 " <toolitem action='SpiralResetAction' />"
362 " </toolbar>"
364 " <toolbar name='PenToolbar'>"
365 " <toolitem action='FreehandModeActionPen' />"
366 " <separator />"
367 " <toolitem action='SetPenShapeAction'/>"
368 " </toolbar>"
370 " <toolbar name='PencilToolbar'>"
371 " <toolitem action='FreehandModeActionPencil' />"
372 " <separator />"
373 " <toolitem action='PencilToleranceAction' />"
374 " <separator />"
375 " <toolitem action='PencilResetAction' />"
376 " <separator />"
377 " <toolitem action='SetPencilShapeAction'/>"
378 " </toolbar>"
380 " <toolbar name='CalligraphyToolbar'>"
381 " <separator />"
382 " <toolitem action='SetProfileAction'/>"
383 " <separator />"
384 " <toolitem action='CalligraphyWidthAction' />"
385 " <toolitem action='PressureAction' />"
386 " <toolitem action='TraceAction' />"
387 " <toolitem action='ThinningAction' />"
388 " <separator />"
389 " <toolitem action='AngleAction' />"
390 " <toolitem action='TiltAction' />"
391 " <toolitem action='FixationAction' />"
392 " <separator />"
393 " <toolitem action='CapRoundingAction' />"
394 " <separator />"
395 " <toolitem action='TremorAction' />"
396 " <toolitem action='WiggleAction' />"
397 " <toolitem action='MassAction' />"
398 " <separator />"
399 " </toolbar>"
401 " <toolbar name='ArcToolbar'>"
402 " <toolitem action='ArcStateAction' />"
403 " <separator />"
404 " <toolitem action='ArcStartAction' />"
405 " <toolitem action='ArcEndAction' />"
406 " <separator />"
407 " <toolitem action='ArcOpenAction' />"
408 " <separator />"
409 " <toolitem action='ArcResetAction' />"
410 " <separator />"
411 " </toolbar>"
413 " <toolbar name='PaintbucketToolbar'>"
414 " <toolitem action='ChannelsAction' />"
415 " <separator />"
416 " <toolitem action='ThresholdAction' />"
417 " <separator />"
418 " <toolitem action='OffsetAction' />"
419 " <toolitem action='PaintbucketUnitsAction' />"
420 " <separator />"
421 " <toolitem action='AutoGapAction' />"
422 " <separator />"
423 " <toolitem action='PaintbucketResetAction' />"
424 " </toolbar>"
426 " <toolbar name='EraserToolbar'>"
427 " <toolitem action='EraserWidthAction' />"
428 " <separator />"
429 " <toolitem action='EraserModeAction' />"
430 " </toolbar>"
432 " <toolbar name='LPEToolToolbar'>"
433 " <toolitem action='LPEToolModeAction' />"
434 " <separator />"
435 " <toolitem action='LPEShowBBoxAction' />"
436 " <toolitem action='LPEBBoxFromSelectionAction' />"
437 " <separator />"
438 " <toolitem action='LPELineSegmentAction' />"
439 " <separator />"
440 " <toolitem action='LPEMeasuringAction' />"
441 " <toolitem action='LPEToolUnitsAction' />"
442 " <separator />"
443 " <toolitem action='LPEOpenLPEDialogAction' />"
444 " </toolbar>"
446 " <toolbar name='DropperToolbar'>"
447 " <toolitem action='DropperOpacityAction' />"
448 " <toolitem action='DropperPickAlphaAction' />"
449 " <toolitem action='DropperSetAlphaAction' />"
450 " </toolbar>"
452 " <toolbar name='ConnectorToolbar'>"
453 " <toolitem action='ConnectorAvoidAction' />"
454 " <toolitem action='ConnectorIgnoreAction' />"
455 " <toolitem action='ConnectorSpacingAction' />"
456 " <toolitem action='ConnectorGraphAction' />"
457 " <toolitem action='ConnectorLengthAction' />"
458 " <toolitem action='ConnectorDirectedAction' />"
459 " <toolitem action='ConnectorOverlapAction' />"
460 " </toolbar>"
462 "</ui>"
463 ;
465 static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop );
467 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
469 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
470 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
472 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
473 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
475 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
476 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
479 GtkWidget * sp_toolbox_button_new_from_verb_with_doubleclick( GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
480 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
481 Inkscape::UI::View::View *view, GtkTooltips *tt);
483 class VerbAction : public Gtk::Action {
484 public:
485 static Glib::RefPtr<VerbAction> create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
487 virtual ~VerbAction();
488 virtual void set_active(bool active = true);
490 protected:
491 virtual Gtk::Widget* create_menu_item_vfunc();
492 virtual Gtk::Widget* create_tool_item_vfunc();
494 virtual void connect_proxy_vfunc(Gtk::Widget* proxy);
495 virtual void disconnect_proxy_vfunc(Gtk::Widget* proxy);
497 virtual void on_activate();
499 private:
500 Inkscape::Verb* verb;
501 Inkscape::Verb* verb2;
502 Inkscape::UI::View::View *view;
503 GtkTooltips *tooltips;
504 bool active;
506 VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
507 };
510 Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips)
511 {
512 Glib::RefPtr<VerbAction> result;
513 SPAction *action = verb->get_action(view);
514 if ( action ) {
515 //SPAction* action2 = verb2 ? verb2->get_action(view) : 0;
516 result = Glib::RefPtr<VerbAction>(new VerbAction(verb, verb2, view, tooltips));
517 }
519 return result;
520 }
522 VerbAction::VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips) :
523 Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(_(verb->get_name())), Glib::ustring(_(verb->get_tip()))),
524 verb(verb),
525 verb2(verb2),
526 view(view),
527 tooltips(tooltips),
528 active(false)
529 {
530 }
532 VerbAction::~VerbAction()
533 {
534 }
536 Gtk::Widget* VerbAction::create_menu_item_vfunc()
537 {
538 // First call in to get the icon rendered if present in SVG
539 Gtk::Widget *widget = sp_icon_get_icon( property_stock_id().get_value().get_string(), Inkscape::ICON_SIZE_MENU );
540 delete widget;
541 widget = 0;
543 Gtk::Widget* widg = Gtk::Action::create_menu_item_vfunc();
544 // g_message("create_menu_item_vfunc() = %p for '%s'", widg, verb->get_id());
545 return widg;
546 }
548 Gtk::Widget* VerbAction::create_tool_item_vfunc()
549 {
550 // Gtk::Widget* widg = Gtk::Action::create_tool_item_vfunc();
551 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/tools/small");
552 GtkWidget* toolbox = 0;
553 GtkWidget *button = sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
554 SP_BUTTON_TYPE_TOGGLE,
555 verb,
556 verb2,
557 view,
558 tooltips );
559 if ( active ) {
560 sp_button_toggle_set_down( SP_BUTTON(button), active);
561 }
562 gtk_widget_show_all( button );
563 Gtk::Widget* wrapped = Glib::wrap(button);
564 Gtk::ToolItem* holder = Gtk::manage(new Gtk::ToolItem());
565 holder->add(*wrapped);
567 // g_message("create_tool_item_vfunc() = %p for '%s'", holder, verb->get_id());
568 return holder;
569 }
571 void VerbAction::connect_proxy_vfunc(Gtk::Widget* proxy)
572 {
573 // g_message("connect_proxy_vfunc(%p) for '%s'", proxy, verb->get_id());
574 Gtk::Action::connect_proxy_vfunc(proxy);
575 }
577 void VerbAction::disconnect_proxy_vfunc(Gtk::Widget* proxy)
578 {
579 // g_message("disconnect_proxy_vfunc(%p) for '%s'", proxy, verb->get_id());
580 Gtk::Action::disconnect_proxy_vfunc(proxy);
581 }
583 void VerbAction::set_active(bool active)
584 {
585 this->active = active;
586 Glib::SListHandle<Gtk::Widget*> proxies = get_proxies();
587 for ( Glib::SListHandle<Gtk::Widget*>::iterator it = proxies.begin(); it != proxies.end(); ++it ) {
588 Gtk::ToolItem* ti = dynamic_cast<Gtk::ToolItem*>(*it);
589 if (ti) {
590 // *should* have one child that is the SPButton
591 Gtk::Widget* child = ti->get_child();
592 if ( child && SP_IS_BUTTON(child->gobj()) ) {
593 SPButton* button = SP_BUTTON(child->gobj());
594 sp_button_toggle_set_down( button, active );
595 }
596 }
597 }
598 }
600 void VerbAction::on_activate()
601 {
602 if ( verb ) {
603 SPAction *action = verb->get_action(view);
604 if ( action ) {
605 sp_action_perform(action, 0);
606 }
607 }
608 }
610 /* Global text entry widgets necessary for update */
611 /* GtkWidget *dropper_rgb_entry,
612 *dropper_opacity_entry ; */
613 // should be made a private member once this is converted to class
615 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
616 connection->disconnect();
617 delete connection;
618 }
620 static void purge_repr_listener( GObject* obj, GObject* tbl )
621 {
622 (void)obj;
623 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
624 if (oldrepr) { // remove old listener
625 sp_repr_remove_listener_by_data(oldrepr, tbl);
626 Inkscape::GC::release(oldrepr);
627 oldrepr = 0;
628 g_object_set_data( tbl, "repr", NULL );
629 }
630 }
632 GtkWidget *
633 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
634 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
635 Inkscape::UI::View::View *view, GtkTooltips *tt)
636 {
637 SPAction *action = verb->get_action(view);
638 if (!action) return NULL;
640 SPAction *doubleclick_action;
641 if (doubleclick_verb)
642 doubleclick_action = doubleclick_verb->get_action(view);
643 else
644 doubleclick_action = NULL;
646 /* fixme: Handle sensitive/unsensitive */
647 /* fixme: Implement sp_button_new_from_action */
648 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
649 gtk_widget_show(b);
652 unsigned int shortcut = sp_shortcut_get_primary(verb);
653 if (shortcut) {
654 gchar key[256];
655 sp_ui_shortcut_string(shortcut, key);
656 gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
657 if ( t ) {
658 gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, tip, 0 );
659 }
660 g_free(tip);
661 } else {
662 if ( t ) {
663 gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, action->tip, 0 );
664 }
665 }
667 return b;
668 }
671 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
672 {
673 SPAction* targetAction = SP_ACTION(user_data);
674 if ( targetAction ) {
675 sp_action_perform( targetAction, NULL );
676 }
677 }
679 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
680 {
681 if ( data ) {
682 GtkAction* act = GTK_ACTION(data);
683 gtk_action_set_sensitive( act, sensitive );
684 }
685 }
687 static SPActionEventVector action_event_vector = {
688 {NULL},
689 NULL,
690 NULL,
691 sp_action_action_set_sensitive,
692 NULL,
693 NULL
694 };
696 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
697 {
698 GtkAction* act = 0;
700 SPAction* targetAction = verb->get_action(view);
701 InkAction* inky = ink_action_new( verb->get_id(), _(verb->get_name()), verb->get_tip(), verb->get_image(), size );
702 act = GTK_ACTION(inky);
703 gtk_action_set_sensitive( act, targetAction->sensitive );
705 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
707 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
708 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
710 return act;
711 }
713 Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop )
714 {
715 Inkscape::UI::View::View *view = desktop;
716 gint verbsToUse[] = {
717 // disabled until we have icons for them:
718 //find
719 //SP_VERB_EDIT_TILE,
720 //SP_VERB_EDIT_UNTILE,
721 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
722 SP_VERB_DIALOG_DISPLAY,
723 SP_VERB_DIALOG_FILL_STROKE,
724 SP_VERB_DIALOG_NAMEDVIEW,
725 SP_VERB_DIALOG_TEXT,
726 SP_VERB_DIALOG_XML_EDITOR,
727 SP_VERB_EDIT_CLONE,
728 SP_VERB_EDIT_COPY,
729 SP_VERB_EDIT_CUT,
730 SP_VERB_EDIT_DUPLICATE,
731 SP_VERB_EDIT_PASTE,
732 SP_VERB_EDIT_REDO,
733 SP_VERB_EDIT_UNDO,
734 SP_VERB_EDIT_UNLINK_CLONE,
735 SP_VERB_FILE_EXPORT,
736 SP_VERB_FILE_IMPORT,
737 SP_VERB_FILE_NEW,
738 SP_VERB_FILE_OPEN,
739 SP_VERB_FILE_PRINT,
740 SP_VERB_FILE_SAVE,
741 SP_VERB_OBJECT_TO_CURVE,
742 SP_VERB_SELECTION_GROUP,
743 SP_VERB_SELECTION_OUTLINE,
744 SP_VERB_SELECTION_UNGROUP,
745 SP_VERB_ZOOM_1_1,
746 SP_VERB_ZOOM_1_2,
747 SP_VERB_ZOOM_2_1,
748 SP_VERB_ZOOM_DRAWING,
749 SP_VERB_ZOOM_IN,
750 SP_VERB_ZOOM_NEXT,
751 SP_VERB_ZOOM_OUT,
752 SP_VERB_ZOOM_PAGE,
753 SP_VERB_ZOOM_PAGE_WIDTH,
754 SP_VERB_ZOOM_PREV,
755 SP_VERB_ZOOM_SELECTION,
756 };
758 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/small");
760 static std::map<SPDesktop*, Glib::RefPtr<Gtk::ActionGroup> > groups;
761 Glib::RefPtr<Gtk::ActionGroup> mainActions;
762 if ( groups.find(desktop) != groups.end() ) {
763 mainActions = groups[desktop];
764 }
766 if ( !mainActions ) {
767 mainActions = Gtk::ActionGroup::create("main");
768 groups[desktop] = mainActions;
769 }
771 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
772 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
773 if ( verb ) {
774 if (!mainActions->get_action(verb->get_id())) {
775 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
776 mainActions->add(Glib::wrap(act));
777 }
778 }
779 }
781 if ( !mainActions->get_action("ToolZoom") ) {
782 GtkTooltips *tt = gtk_tooltips_new();
783 for ( guint i = 0; i < G_N_ELEMENTS(tools) && tools[i].type_name; i++ ) {
784 Glib::RefPtr<VerbAction> va = VerbAction::create(Inkscape::Verb::get(tools[i].verb), Inkscape::Verb::get(tools[i].doubleclick_verb), view, tt);
785 if ( va ) {
786 mainActions->add(va);
787 if ( i == 0 ) {
788 va->set_active(true);
789 }
790 }
791 }
792 }
795 return mainActions;
796 }
799 void handlebox_detached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
800 {
801 gtk_widget_set_size_request( widget,
802 widget->allocation.width,
803 widget->allocation.height );
804 }
806 void handlebox_attached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
807 {
808 gtk_widget_set_size_request( widget, -1, -1 );
809 }
813 GtkWidget *
814 sp_tool_toolbox_new()
815 {
816 GtkTooltips *tt = gtk_tooltips_new();
817 GtkWidget* tb = gtk_toolbar_new();
818 gtk_toolbar_set_orientation(GTK_TOOLBAR(tb), GTK_ORIENTATION_VERTICAL);
819 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(tb), TRUE);
821 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
822 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
824 gtk_widget_set_sensitive(tb, FALSE);
826 GtkWidget *hb = gtk_handle_box_new();
827 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
828 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
829 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
831 gtk_container_add(GTK_CONTAINER(hb), tb);
832 gtk_widget_show(GTK_WIDGET(tb));
834 sigc::connection* conn = new sigc::connection;
835 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
837 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
838 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
840 return hb;
841 }
843 GtkWidget *
844 sp_aux_toolbox_new()
845 {
846 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
848 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
850 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
852 gtk_widget_set_sensitive(tb, FALSE);
854 GtkWidget *hb = gtk_handle_box_new();
855 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
856 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
857 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
859 gtk_container_add(GTK_CONTAINER(hb), tb);
860 gtk_widget_show(GTK_WIDGET(tb));
862 sigc::connection* conn = new sigc::connection;
863 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
865 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
866 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
868 return hb;
869 }
871 //####################################
872 //# Commands Bar
873 //####################################
875 GtkWidget *
876 sp_commands_toolbox_new()
877 {
878 GtkWidget *tb = gtk_toolbar_new();
880 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
881 gtk_widget_set_sensitive(tb, FALSE);
883 GtkWidget *hb = gtk_handle_box_new();
884 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
885 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
886 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
888 gtk_container_add(GTK_CONTAINER(hb), tb);
889 gtk_widget_show(GTK_WIDGET(tb));
891 sigc::connection* conn = new sigc::connection;
892 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
894 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
895 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
897 return hb;
898 }
901 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
902 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
903 Glib::ustring const &path, gdouble def,
904 GtkWidget *focusTarget,
905 GtkWidget *us,
906 GObject *dataKludge,
907 gboolean altx, gchar const *altx_mark,
908 gdouble lower, gdouble upper, gdouble step, gdouble page,
909 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
910 void (*callback)(GtkAdjustment *, GObject *),
911 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
912 {
913 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
914 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs->getDouble(path, def) * factor,
915 lower, upper, step, page, page ) );
916 if (us) {
917 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
918 }
920 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
922 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
923 if ( shortLabel ) {
924 g_object_set( act, "short_label", shortLabel, NULL );
925 }
927 if ( (descrCount > 0) && descrLabels && descrValues ) {
928 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
929 }
931 if ( focusTarget ) {
932 ege_adjustment_action_set_focuswidget( act, focusTarget );
933 }
935 if ( altx && altx_mark ) {
936 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
937 }
939 if ( dataKludge ) {
940 // Rather lame, but it's the only place where we need to get the entry name
941 // but we don't have an Entry
942 g_object_set_data( dataKludge, prefs->getEntry(path).getEntryName().data(), adj );
943 }
945 // Using a cast just to make sure we pass in the right kind of function pointer
946 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
948 return act;
949 }
952 //####################################
953 //# node editing callbacks
954 //####################################
956 /**
957 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
958 */
959 static ShapeEditor *get_current_shape_editor()
960 {
961 if (!SP_ACTIVE_DESKTOP) {
962 return NULL;
963 }
965 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
967 if (!SP_IS_NODE_CONTEXT(event_context)) {
968 return NULL;
969 }
971 return SP_NODE_CONTEXT(event_context)->shape_editor;
972 }
975 void
976 sp_node_path_edit_add(void)
977 {
978 ShapeEditor *shape_editor = get_current_shape_editor();
979 if (shape_editor) shape_editor->add_node();
980 }
982 void
983 sp_node_path_edit_delete(void)
984 {
985 ShapeEditor *shape_editor = get_current_shape_editor();
986 if (shape_editor) shape_editor->delete_nodes_preserving_shape();
987 }
989 void
990 sp_node_path_edit_delete_segment(void)
991 {
992 ShapeEditor *shape_editor = get_current_shape_editor();
993 if (shape_editor) shape_editor->delete_segment();
994 }
996 void
997 sp_node_path_edit_break(void)
998 {
999 ShapeEditor *shape_editor = get_current_shape_editor();
1000 if (shape_editor) shape_editor->break_at_nodes();
1001 }
1003 void
1004 sp_node_path_edit_join(void)
1005 {
1006 ShapeEditor *shape_editor = get_current_shape_editor();
1007 if (shape_editor) shape_editor->join_nodes();
1008 }
1010 void
1011 sp_node_path_edit_join_segment(void)
1012 {
1013 ShapeEditor *shape_editor = get_current_shape_editor();
1014 if (shape_editor) shape_editor->join_segments();
1015 }
1017 void
1018 sp_node_path_edit_toline(void)
1019 {
1020 ShapeEditor *shape_editor = get_current_shape_editor();
1021 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
1022 }
1024 void
1025 sp_node_path_edit_tocurve(void)
1026 {
1027 ShapeEditor *shape_editor = get_current_shape_editor();
1028 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
1029 }
1031 void
1032 sp_node_path_edit_cusp(void)
1033 {
1034 ShapeEditor *shape_editor = get_current_shape_editor();
1035 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
1036 }
1038 void
1039 sp_node_path_edit_smooth(void)
1040 {
1041 ShapeEditor *shape_editor = get_current_shape_editor();
1042 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
1043 }
1045 void
1046 sp_node_path_edit_symmetrical(void)
1047 {
1048 ShapeEditor *shape_editor = get_current_shape_editor();
1049 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
1050 }
1052 void
1053 sp_node_path_edit_auto(void)
1054 {
1055 ShapeEditor *shape_editor = get_current_shape_editor();
1056 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_AUTO);
1057 }
1059 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
1060 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1061 bool show = gtk_toggle_action_get_active( act );
1062 prefs->setBool("/tools/nodes/show_handles", show);
1063 ShapeEditor *shape_editor = get_current_shape_editor();
1064 if (shape_editor) shape_editor->show_handles(show);
1065 }
1067 static void toggle_show_helperpath (GtkToggleAction *act, gpointer /*data*/) {
1068 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1069 bool show = gtk_toggle_action_get_active( act );
1070 prefs->setBool("/tools/nodes/show_helperpath", show);
1071 ShapeEditor *shape_editor = get_current_shape_editor();
1072 if (shape_editor) shape_editor->show_helperpath(show);
1073 }
1075 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
1076 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
1077 }
1079 void sp_node_path_edit_clippath (GtkAction */*act*/, gpointer data) {
1080 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), true);
1081 }
1083 void sp_node_path_edit_maskpath (GtkAction */*act*/, gpointer data) {
1084 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), false);
1085 }
1087 /* is called when the node selection is modified */
1088 static void
1089 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
1090 {
1091 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
1092 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
1093 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
1094 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
1096 // quit if run by the attr_changed listener
1097 if (g_object_get_data( tbl, "freeze" )) {
1098 return;
1099 }
1101 // in turn, prevent listener from responding
1102 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1104 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1105 SPUnit const *unit = tracker->getActiveUnit();
1107 ShapeEditor *shape_editor = get_current_shape_editor();
1108 if (shape_editor && shape_editor->has_nodepath()) {
1109 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
1110 int n_selected = 0;
1111 if (nodepath) {
1112 n_selected = nodepath->numSelected();
1113 }
1115 if (n_selected == 0) {
1116 gtk_action_set_sensitive(xact, FALSE);
1117 gtk_action_set_sensitive(yact, FALSE);
1118 } else {
1119 gtk_action_set_sensitive(xact, TRUE);
1120 gtk_action_set_sensitive(yact, TRUE);
1121 Geom::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
1122 Geom::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
1124 if (n_selected == 1) {
1125 Geom::Point sel_node = nodepath->singleSelectedCoords();
1126 if (oldx != sel_node[Geom::X] || oldy != sel_node[Geom::Y]) {
1127 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[Geom::X], *unit));
1128 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[Geom::Y], *unit));
1129 }
1130 } else {
1131 boost::optional<Geom::Coord> x = sp_node_selected_common_coord(nodepath, Geom::X);
1132 boost::optional<Geom::Coord> y = sp_node_selected_common_coord(nodepath, Geom::Y);
1133 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
1134 /* Note: Currently x and y will always have a value, even if the coordinates of the
1135 selected nodes don't coincide (in this case we use the coordinates of the center
1136 of the bounding box). So the entries are never set to zero. */
1137 // FIXME: Maybe we should clear the entry if several nodes are selected
1138 // instead of providing a kind of average value
1139 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
1140 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
1141 }
1142 }
1143 }
1144 } else {
1145 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
1146 gtk_action_set_sensitive(xact, FALSE);
1147 gtk_action_set_sensitive(yact, FALSE);
1148 }
1150 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1151 }
1153 static void
1154 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
1155 {
1156 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1157 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1159 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1160 SPUnit const *unit = tracker->getActiveUnit();
1162 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1163 prefs->setDouble(Glib::ustring("/tools/nodes/") + value_name, sp_units_get_pixels(adj->value, *unit));
1164 }
1166 // quit if run by the attr_changed listener
1167 if (g_object_get_data( tbl, "freeze" )) {
1168 return;
1169 }
1171 // in turn, prevent listener from responding
1172 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1174 ShapeEditor *shape_editor = get_current_shape_editor();
1175 if (shape_editor && shape_editor->has_nodepath()) {
1176 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
1177 if (!strcmp(value_name, "x")) {
1178 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, Geom::X);
1179 }
1180 if (!strcmp(value_name, "y")) {
1181 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, Geom::Y);
1182 }
1183 }
1185 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1186 }
1188 static void
1189 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
1190 {
1191 sp_node_path_value_changed(adj, tbl, "x");
1192 }
1194 static void
1195 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
1196 {
1197 sp_node_path_value_changed(adj, tbl, "y");
1198 }
1200 void
1201 sp_node_toolbox_sel_changed (Inkscape::Selection *selection, GObject *tbl)
1202 {
1203 {
1204 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_lpeedit" ) );
1205 SPItem *item = selection->singleItem();
1206 if (item && SP_IS_LPE_ITEM(item)) {
1207 if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(item))) {
1208 gtk_action_set_sensitive(w, TRUE);
1209 } else {
1210 gtk_action_set_sensitive(w, FALSE);
1211 }
1212 } else {
1213 gtk_action_set_sensitive(w, FALSE);
1214 }
1215 }
1217 {
1218 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_clippathedit" ) );
1219 SPItem *item = selection->singleItem();
1220 if (item && item->clip_ref && item->clip_ref->getObject()) {
1221 gtk_action_set_sensitive(w, TRUE);
1222 } else {
1223 gtk_action_set_sensitive(w, FALSE);
1224 }
1225 }
1227 {
1228 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_maskedit" ) );
1229 SPItem *item = selection->singleItem();
1230 if (item && item->mask_ref && item->mask_ref->getObject()) {
1231 gtk_action_set_sensitive(w, TRUE);
1232 } else {
1233 gtk_action_set_sensitive(w, FALSE);
1234 }
1235 }
1236 }
1238 void
1239 sp_node_toolbox_sel_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
1240 {
1241 sp_node_toolbox_sel_changed (selection, tbl);
1242 }
1246 //################################
1247 //## Node Editing Toolbox ##
1248 //################################
1250 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1251 {
1252 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1253 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1254 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1255 g_object_set_data( holder, "tracker", tracker );
1257 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
1259 {
1260 InkAction* inky = ink_action_new( "NodeInsertAction",
1261 _("Insert node"),
1262 _("Insert new nodes into selected segments"),
1263 "node_insert",
1264 secondarySize );
1265 g_object_set( inky, "short_label", _("Insert"), NULL );
1266 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
1267 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1268 }
1270 {
1271 InkAction* inky = ink_action_new( "NodeDeleteAction",
1272 _("Delete node"),
1273 _("Delete selected nodes"),
1274 "node_delete",
1275 secondarySize );
1276 g_object_set( inky, "short_label", _("Delete"), NULL );
1277 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
1278 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1279 }
1281 {
1282 InkAction* inky = ink_action_new( "NodeJoinAction",
1283 _("Join endnodes"),
1284 _("Join selected endnodes"),
1285 "node_join",
1286 secondarySize );
1287 g_object_set( inky, "short_label", _("Join"), NULL );
1288 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1289 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1290 }
1292 {
1293 InkAction* inky = ink_action_new( "NodeBreakAction",
1294 _("Break nodes"),
1295 _("Break path at selected nodes"),
1296 "node_break",
1297 secondarySize );
1298 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1299 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1300 }
1303 {
1304 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1305 _("Join with segment"),
1306 _("Join selected endnodes with a new segment"),
1307 "node_join_segment",
1308 secondarySize );
1309 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1310 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1311 }
1313 {
1314 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1315 _("Delete segment"),
1316 _("Delete segment between two non-endpoint nodes"),
1317 "node_delete_segment",
1318 secondarySize );
1319 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1320 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1321 }
1323 {
1324 InkAction* inky = ink_action_new( "NodeCuspAction",
1325 _("Node Cusp"),
1326 _("Make selected nodes corner"),
1327 "node_cusp",
1328 secondarySize );
1329 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1330 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1331 }
1333 {
1334 InkAction* inky = ink_action_new( "NodeSmoothAction",
1335 _("Node Smooth"),
1336 _("Make selected nodes smooth"),
1337 "node_smooth",
1338 secondarySize );
1339 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1340 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1341 }
1343 {
1344 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1345 _("Node Symmetric"),
1346 _("Make selected nodes symmetric"),
1347 "node_symmetric",
1348 secondarySize );
1349 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1350 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1351 }
1353 {
1354 InkAction* inky = ink_action_new( "NodeAutoAction",
1355 _("Node Auto"),
1356 _("Make selected nodes auto-smooth"),
1357 "node_auto",
1358 secondarySize );
1359 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_auto), 0 );
1360 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1361 }
1363 {
1364 InkAction* inky = ink_action_new( "NodeLineAction",
1365 _("Node Line"),
1366 _("Make selected segments lines"),
1367 "node_line",
1368 secondarySize );
1369 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1370 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1371 }
1373 {
1374 InkAction* inky = ink_action_new( "NodeCurveAction",
1375 _("Node Curve"),
1376 _("Make selected segments curves"),
1377 "node_curve",
1378 secondarySize );
1379 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1380 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1381 }
1383 {
1384 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1385 _("Show Handles"),
1386 _("Show the Bezier handles of selected nodes"),
1387 "nodes_show_handles",
1388 Inkscape::ICON_SIZE_DECORATION );
1389 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1390 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1391 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/nodes/show_handles", true) );
1392 }
1394 {
1395 InkToggleAction* act = ink_toggle_action_new( "NodesShowHelperpath",
1396 _("Show Outline"),
1397 _("Show the outline of the path"),
1398 "nodes_show_helperpath",
1399 Inkscape::ICON_SIZE_DECORATION );
1400 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1401 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_helperpath), desktop );
1402 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/nodes/show_helperpath", false) );
1403 }
1405 {
1406 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1407 _("Next path effect parameter"),
1408 _("Show next path effect parameter for editing"),
1409 "edit_next_parameter",
1410 Inkscape::ICON_SIZE_DECORATION );
1411 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1412 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1413 g_object_set_data( holder, "nodes_lpeedit", inky);
1414 }
1416 {
1417 InkAction* inky = ink_action_new( "ObjectEditClipPathAction",
1418 _("Edit clipping path"),
1419 _("Edit the clipping path of the object"),
1420 "nodeedit-clippath",
1421 Inkscape::ICON_SIZE_DECORATION );
1422 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_clippath), desktop );
1423 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1424 g_object_set_data( holder, "nodes_clippathedit", inky);
1425 }
1427 {
1428 InkAction* inky = ink_action_new( "ObjectEditMaskPathAction",
1429 _("Edit mask path"),
1430 _("Edit the mask of the object"),
1431 "nodeedit-mask",
1432 Inkscape::ICON_SIZE_DECORATION );
1433 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_maskpath), desktop );
1434 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1435 g_object_set_data( holder, "nodes_maskedit", inky);
1436 }
1438 /* X coord of selected node(s) */
1439 {
1440 EgeAdjustmentAction* eact = 0;
1441 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1442 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1443 eact = create_adjustment_action( "NodeXAction",
1444 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1445 "/tools/nodes/Xcoord", 0,
1446 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1447 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1448 labels, values, G_N_ELEMENTS(labels),
1449 sp_node_path_x_value_changed );
1450 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1451 g_object_set_data( holder, "nodes_x_action", eact );
1452 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1453 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1454 }
1456 /* Y coord of selected node(s) */
1457 {
1458 EgeAdjustmentAction* eact = 0;
1459 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1460 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1461 eact = create_adjustment_action( "NodeYAction",
1462 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1463 "/tools/nodes/Ycoord", 0,
1464 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1465 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1466 labels, values, G_N_ELEMENTS(labels),
1467 sp_node_path_y_value_changed );
1468 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1469 g_object_set_data( holder, "nodes_y_action", eact );
1470 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1471 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1472 }
1474 // add the units menu
1475 {
1476 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1477 gtk_action_group_add_action( mainActions, act );
1478 }
1481 sp_node_toolbox_sel_changed(sp_desktop_selection(desktop), holder);
1483 //watch selection
1484 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
1486 sigc::connection *c_selection_changed =
1487 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
1488 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_changed), (GObject*)holder)));
1489 pool->add_connection ("selection-changed", c_selection_changed);
1491 sigc::connection *c_selection_modified =
1492 new sigc::connection (sp_desktop_selection (desktop)->connectModified
1493 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_modified), (GObject*)holder)));
1494 pool->add_connection ("selection-modified", c_selection_modified);
1496 sigc::connection *c_subselection_changed =
1497 new sigc::connection (desktop->connectToolSubselectionChanged
1498 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_coord_changed), (GObject*)holder)));
1499 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
1501 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool);
1503 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1504 } // end of sp_node_toolbox_prep()
1507 //########################
1508 //## Zoom Toolbox ##
1509 //########################
1511 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1512 {
1513 // no custom GtkAction setup needed
1514 } // end of sp_zoom_toolbox_prep()
1516 void
1517 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1518 {
1519 toolbox_set_desktop(toolbox,
1520 desktop,
1521 setup_tool_toolbox,
1522 update_tool_toolbox,
1523 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1524 "event_context_connection")));
1525 }
1528 void
1529 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1530 {
1531 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)),
1532 desktop,
1533 setup_aux_toolbox,
1534 update_aux_toolbox,
1535 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1536 "event_context_connection")));
1537 }
1539 void
1540 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1541 {
1542 toolbox_set_desktop(toolbox,
1543 desktop,
1544 setup_commands_toolbox,
1545 update_commands_toolbox,
1546 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1547 "event_context_connection")));
1548 }
1550 static void
1551 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1552 {
1553 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1554 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1556 if (old_desktop) {
1557 GList *children, *iter;
1559 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1560 for ( iter = children ; iter ; iter = iter->next ) {
1561 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1562 }
1563 g_list_free(children);
1564 }
1566 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1568 if (desktop) {
1569 gtk_widget_set_sensitive(toolbox, TRUE);
1570 setup_func(toolbox, desktop);
1571 update_func(desktop, desktop->event_context, toolbox);
1572 *conn = desktop->connectEventContextChanged
1573 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1574 } else {
1575 gtk_widget_set_sensitive(toolbox, FALSE);
1576 }
1578 } // end of toolbox_set_desktop()
1581 static void
1582 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1583 {
1584 gchar const * descr =
1585 "<ui>"
1586 " <toolbar name='ToolToolbar'>"
1587 " <toolitem action='ToolSelector' />"
1588 " <toolitem action='ToolNode' />"
1589 " <toolitem action='ToolTweak' />"
1590 " <toolitem action='ToolZoom' />"
1591 " <toolitem action='ToolRect' />"
1592 " <toolitem action='Tool3DBox' />"
1593 " <toolitem action='ToolArc' />"
1594 " <toolitem action='ToolStar' />"
1595 " <toolitem action='ToolSpiral' />"
1596 " <toolitem action='ToolPencil' />"
1597 " <toolitem action='ToolPen' />"
1598 " <toolitem action='ToolCalligraphic' />"
1599 " <toolitem action='ToolEraser' />"
1600 // " <toolitem action='ToolLPETool' />"
1601 " <toolitem action='ToolPaintBucket' />"
1602 " <toolitem action='ToolText' />"
1603 " <toolitem action='ToolConnector' />"
1604 " <toolitem action='ToolGradient' />"
1605 " <toolitem action='ToolDropper' />"
1606 " </toolbar>"
1607 "</ui>";
1608 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1609 GtkUIManager* mgr = gtk_ui_manager_new();
1610 GError* errVal = 0;
1611 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1613 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1614 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1616 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/ToolToolbar" );
1617 if ( prefs->getBool("/toolbox/icononly", true) ) {
1618 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1619 }
1620 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/tools/small");
1621 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1623 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_VERTICAL);
1624 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
1626 g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
1628 GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
1629 if ( child ) {
1630 gtk_container_remove( GTK_CONTAINER(toolbox), child );
1631 }
1633 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1634 // Inkscape::IconSize toolboxSize = prefToSize("/toolbox/tools/small");
1635 }
1638 static void
1639 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget */*toolbox*/ )
1640 {
1641 gchar const *const tname = ( eventcontext
1642 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1643 : NULL );
1644 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1646 for (int i = 0 ; tools[i].type_name ; i++ ) {
1647 Glib::RefPtr<Gtk::Action> act = mainActions->get_action( Inkscape::Verb::get(tools[i].verb)->get_id() );
1648 if ( act ) {
1649 bool setActive = tname && !strcmp(tname, tools[i].type_name);
1650 Glib::RefPtr<VerbAction> verbAct = Glib::RefPtr<VerbAction>::cast_dynamic(act);
1651 if ( verbAct ) {
1652 verbAct->set_active(setActive);
1653 }
1654 }
1655 }
1656 }
1658 static void
1659 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1660 {
1661 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1662 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1663 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1664 GtkUIManager* mgr = gtk_ui_manager_new();
1665 GError* errVal = 0;
1666 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1667 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1669 std::map<std::string, GtkWidget*> dataHolders;
1671 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1672 if ( aux_toolboxes[i].prep_func ) {
1673 // converted to GtkActions and UIManager
1675 GtkWidget* kludge = gtk_toolbar_new();
1676 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1677 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1678 dataHolders[aux_toolboxes[i].type_name] = kludge;
1679 aux_toolboxes[i].prep_func( desktop, mainActions->gobj(), G_OBJECT(kludge) );
1680 } else {
1682 GtkWidget *sub_toolbox = 0;
1683 if (aux_toolboxes[i].create_func == NULL)
1684 sub_toolbox = sp_empty_toolbox_new(desktop);
1685 else {
1686 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1687 }
1689 gtk_size_group_add_widget( grouper, sub_toolbox );
1691 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1692 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1694 }
1695 }
1697 // Second pass to create toolbars *after* all GtkActions are created
1698 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1699 if ( aux_toolboxes[i].prep_func ) {
1700 // converted to GtkActions and UIManager
1702 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1704 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1705 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1707 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1708 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1709 g_free( tmp );
1710 tmp = 0;
1712 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/small");
1713 if ( prefs->getBool( "/toolbox/icononly", true) ) {
1714 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1715 }
1716 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1719 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1721 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1722 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, _(aux_toolboxes[i].swatch_tip) );
1723 swatch->setDesktop( desktop );
1724 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1725 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1726 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1727 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 );
1728 }
1730 gtk_widget_show_all( holder );
1731 sp_set_font_size_smaller( holder );
1733 gtk_size_group_add_widget( grouper, holder );
1735 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1736 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1737 }
1738 }
1740 g_object_unref( G_OBJECT(grouper) );
1741 }
1743 static void
1744 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1745 {
1746 gchar const *tname = ( eventcontext
1747 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1748 : NULL );
1749 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1750 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1751 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1752 gtk_widget_show_all(sub_toolbox);
1753 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1754 } else {
1755 gtk_widget_hide(sub_toolbox);
1756 }
1757 }
1758 }
1760 static void
1761 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1762 {
1763 gchar const * descr =
1764 "<ui>"
1765 " <toolbar name='CommandsToolbar'>"
1766 " <toolitem action='FileNew' />"
1767 " <toolitem action='FileOpen' />"
1768 " <toolitem action='FileSave' />"
1769 " <toolitem action='FilePrint' />"
1770 " <separator />"
1771 " <toolitem action='FileImport' />"
1772 " <toolitem action='FileExport' />"
1773 " <separator />"
1774 " <toolitem action='EditUndo' />"
1775 " <toolitem action='EditRedo' />"
1776 " <separator />"
1777 " <toolitem action='EditCopy' />"
1778 " <toolitem action='EditCut' />"
1779 " <toolitem action='EditPaste' />"
1780 " <separator />"
1781 " <toolitem action='ZoomSelection' />"
1782 " <toolitem action='ZoomDrawing' />"
1783 " <toolitem action='ZoomPage' />"
1784 " <separator />"
1785 " <toolitem action='EditDuplicate' />"
1786 " <toolitem action='EditClone' />"
1787 " <toolitem action='EditUnlinkClone' />"
1788 " <separator />"
1789 " <toolitem action='SelectionGroup' />"
1790 " <toolitem action='SelectionUnGroup' />"
1791 " <separator />"
1792 " <toolitem action='DialogFillStroke' />"
1793 " <toolitem action='DialogText' />"
1794 " <toolitem action='DialogXMLEditor' />"
1795 " <toolitem action='DialogAlignDistribute' />"
1796 " <separator />"
1797 " <toolitem action='DialogPreferences' />"
1798 " <toolitem action='DialogDocumentProperties' />"
1799 " </toolbar>"
1800 "</ui>";
1801 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1802 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1804 GtkUIManager* mgr = gtk_ui_manager_new();
1805 GError* errVal = 0;
1807 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1808 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1810 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1811 if ( prefs->getBool("/toolbox/icononly", true) ) {
1812 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1813 }
1815 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/small");
1816 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1818 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_HORIZONTAL);
1819 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
1822 g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
1824 GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
1825 if ( child ) {
1826 gtk_container_remove( GTK_CONTAINER(toolbox), child );
1827 }
1829 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1830 }
1832 static void
1833 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1834 {
1835 }
1837 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1838 {
1839 gtk_widget_show(toolbox_toplevel);
1840 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1842 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1843 if (!shown_toolbox) {
1844 return;
1845 }
1846 gtk_widget_show(toolbox);
1848 gtk_widget_show_all(shown_toolbox);
1849 }
1851 static GtkWidget *
1852 sp_empty_toolbox_new(SPDesktop *desktop)
1853 {
1854 GtkWidget *tbl = gtk_toolbar_new();
1855 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1856 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1858 gtk_widget_show_all(tbl);
1859 sp_set_font_size_smaller (tbl);
1861 return tbl;
1862 }
1864 #define MODE_LABEL_WIDTH 70
1866 //########################
1867 //## Star ##
1868 //########################
1870 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1871 {
1872 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1874 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1875 // do not remember prefs if this call is initiated by an undo change, because undoing object
1876 // creation sets bogus values to its attributes before it is deleted
1877 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1878 prefs->setInt("/tools/shapes/star/magnitude", (gint)adj->value);
1879 }
1881 // quit if run by the attr_changed listener
1882 if (g_object_get_data( dataKludge, "freeze" )) {
1883 return;
1884 }
1886 // in turn, prevent listener from responding
1887 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1889 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);
1896 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1897 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1898 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1899 + M_PI / (gint)adj->value));
1900 SP_OBJECT((SPItem *) items->data)->updateRepr();
1901 modmade = true;
1902 }
1903 }
1904 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1905 _("Star: Change number of corners"));
1907 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1908 }
1910 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1911 {
1912 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1914 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1915 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1916 prefs->setDouble("/tools/shapes/star/proportion", adj->value);
1917 }
1919 // quit if run by the attr_changed listener
1920 if (g_object_get_data( dataKludge, "freeze" )) {
1921 return;
1922 }
1924 // in turn, prevent listener from responding
1925 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1927 bool modmade = false;
1928 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1929 GSList const *items = selection->itemList();
1930 for (; items != NULL; items = items->next) {
1931 if (SP_IS_STAR((SPItem *) items->data)) {
1932 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1934 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1935 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1936 if (r2 < r1) {
1937 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1938 } else {
1939 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1940 }
1942 SP_OBJECT((SPItem *) items->data)->updateRepr();
1943 modmade = true;
1944 }
1945 }
1947 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1948 _("Star: Change spoke ratio"));
1950 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1951 }
1953 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1954 {
1955 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1956 bool flat = ege_select_one_action_get_active( act ) == 0;
1958 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1959 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1960 prefs->setBool( "/tools/shapes/star/isflatsided", flat);
1961 }
1963 // quit if run by the attr_changed listener
1964 if (g_object_get_data( dataKludge, "freeze" )) {
1965 return;
1966 }
1968 // in turn, prevent listener from responding
1969 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1971 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1972 GSList const *items = selection->itemList();
1973 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1974 bool modmade = false;
1976 if ( prop_action ) {
1977 gtk_action_set_sensitive( prop_action, !flat );
1978 }
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 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1984 SP_OBJECT((SPItem *) items->data)->updateRepr();
1985 modmade = true;
1986 }
1987 }
1989 if (modmade) {
1990 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1991 flat ? _("Make polygon") : _("Make star"));
1992 }
1994 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1995 }
1997 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1998 {
1999 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2001 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2002 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2003 prefs->setDouble("/tools/shapes/star/rounded", (gdouble) adj->value);
2004 }
2006 // quit if run by the attr_changed listener
2007 if (g_object_get_data( dataKludge, "freeze" )) {
2008 return;
2009 }
2011 // in turn, prevent listener from responding
2012 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2014 bool modmade = false;
2016 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2017 GSList const *items = selection->itemList();
2018 for (; items != NULL; items = items->next) {
2019 if (SP_IS_STAR((SPItem *) items->data)) {
2020 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2021 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
2022 SP_OBJECT(items->data)->updateRepr();
2023 modmade = true;
2024 }
2025 }
2026 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2027 _("Star: Change rounding"));
2029 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2030 }
2032 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
2033 {
2034 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2036 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2037 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2038 prefs->setDouble("/tools/shapes/star/randomized", (gdouble) adj->value);
2039 }
2041 // quit if run by the attr_changed listener
2042 if (g_object_get_data( dataKludge, "freeze" )) {
2043 return;
2044 }
2046 // in turn, prevent listener from responding
2047 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2049 bool modmade = false;
2051 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2052 GSList const *items = selection->itemList();
2053 for (; items != NULL; items = items->next) {
2054 if (SP_IS_STAR((SPItem *) items->data)) {
2055 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2056 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
2057 SP_OBJECT(items->data)->updateRepr();
2058 modmade = true;
2059 }
2060 }
2061 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2062 _("Star: Change randomization"));
2064 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2065 }
2068 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2069 gchar const */*old_value*/, gchar const */*new_value*/,
2070 bool /*is_interactive*/, gpointer data)
2071 {
2072 GtkWidget *tbl = GTK_WIDGET(data);
2074 // quit if run by the _changed callbacks
2075 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2076 return;
2077 }
2079 // in turn, prevent callbacks from responding
2080 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2082 GtkAdjustment *adj = 0;
2084 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2085 bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true);
2087 if (!strcmp(name, "inkscape:randomized")) {
2088 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
2089 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
2090 } else if (!strcmp(name, "inkscape:rounded")) {
2091 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
2092 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
2093 } else if (!strcmp(name, "inkscape:flatsided")) {
2094 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
2095 char const *flatsides = repr->attribute("inkscape:flatsided");
2096 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
2097 if ( flatsides && !strcmp(flatsides,"false") ) {
2098 ege_select_one_action_set_active( flat_action, 1 );
2099 gtk_action_set_sensitive( prop_action, TRUE );
2100 } else {
2101 ege_select_one_action_set_active( flat_action, 0 );
2102 gtk_action_set_sensitive( prop_action, FALSE );
2103 }
2104 } else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) {
2105 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
2106 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
2107 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
2108 if (r2 < r1) {
2109 gtk_adjustment_set_value(adj, r2/r1);
2110 } else {
2111 gtk_adjustment_set_value(adj, r1/r2);
2112 }
2113 } else if (!strcmp(name, "sodipodi:sides")) {
2114 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
2115 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
2116 }
2118 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2119 }
2122 static Inkscape::XML::NodeEventVector star_tb_repr_events =
2123 {
2124 NULL, /* child_added */
2125 NULL, /* child_removed */
2126 star_tb_event_attr_changed,
2127 NULL, /* content_changed */
2128 NULL /* order_changed */
2129 };
2132 /**
2133 * \param selection Should not be NULL.
2134 */
2135 static void
2136 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2137 {
2138 int n_selected = 0;
2139 Inkscape::XML::Node *repr = NULL;
2141 purge_repr_listener( tbl, tbl );
2143 for (GSList const *items = selection->itemList();
2144 items != NULL;
2145 items = items->next)
2146 {
2147 if (SP_IS_STAR((SPItem *) items->data)) {
2148 n_selected++;
2149 repr = SP_OBJECT_REPR((SPItem *) items->data);
2150 }
2151 }
2153 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2155 if (n_selected == 0) {
2156 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2157 } else if (n_selected == 1) {
2158 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2160 if (repr) {
2161 g_object_set_data( tbl, "repr", repr );
2162 Inkscape::GC::anchor(repr);
2163 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
2164 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
2165 }
2166 } else {
2167 // FIXME: implement averaging of all parameters for multiple selected stars
2168 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2169 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2170 }
2171 }
2174 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
2175 {
2176 // FIXME: in this and all other _default functions, set some flag telling the value_changed
2177 // callbacks to lump all the changes for all selected objects in one undo step
2179 GtkAdjustment *adj = 0;
2181 // fixme: make settable in prefs!
2182 gint mag = 5;
2183 gdouble prop = 0.5;
2184 gboolean flat = FALSE;
2185 gdouble randomized = 0;
2186 gdouble rounded = 0;
2188 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
2189 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
2191 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
2192 gtk_action_set_sensitive( sb2, !flat );
2194 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
2195 gtk_adjustment_set_value(adj, mag);
2196 gtk_adjustment_value_changed(adj);
2198 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
2199 gtk_adjustment_set_value(adj, prop);
2200 gtk_adjustment_value_changed(adj);
2202 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
2203 gtk_adjustment_set_value(adj, rounded);
2204 gtk_adjustment_value_changed(adj);
2206 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
2207 gtk_adjustment_set_value(adj, randomized);
2208 gtk_adjustment_value_changed(adj);
2209 }
2212 void
2213 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
2214 {
2215 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
2216 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
2217 GtkWidget *l = gtk_label_new(NULL);
2218 gtk_label_set_markup(GTK_LABEL(l), title);
2219 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
2220 if ( GTK_IS_TOOLBAR(tbl) ) {
2221 gtk_toolbar_append_widget( GTK_TOOLBAR(tbl), boxl, "", "" );
2222 } else {
2223 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
2224 }
2225 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
2226 }
2229 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2230 {
2231 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
2233 {
2234 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
2235 ege_output_action_set_use_markup( act, TRUE );
2236 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2237 g_object_set_data( holder, "mode_action", act );
2238 }
2240 {
2241 EgeAdjustmentAction* eact = 0;
2242 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2243 bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true);
2245 /* Flatsided checkbox */
2246 {
2247 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2249 GtkTreeIter iter;
2250 gtk_list_store_append( model, &iter );
2251 gtk_list_store_set( model, &iter,
2252 0, _("Polygon"),
2253 1, _("Regular polygon (with one handle) instead of a star"),
2254 2, "star_flat",
2255 -1 );
2257 gtk_list_store_append( model, &iter );
2258 gtk_list_store_set( model, &iter,
2259 0, _("Star"),
2260 1, _("Star instead of a regular polygon (with one handle)"),
2261 2, "star_angled",
2262 -1 );
2264 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
2265 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2266 g_object_set_data( holder, "flat_action", act );
2268 ege_select_one_action_set_appearance( act, "full" );
2269 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2270 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2271 ege_select_one_action_set_icon_column( act, 2 );
2272 ege_select_one_action_set_icon_size( act, secondarySize );
2273 ege_select_one_action_set_tooltip_column( act, 1 );
2275 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
2276 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
2277 }
2279 /* Magnitude */
2280 {
2281 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
2282 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
2283 eact = create_adjustment_action( "MagnitudeAction",
2284 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
2285 "/tools/shapes/star/magnitude", 3,
2286 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2287 3, 1024, 1, 5,
2288 labels, values, G_N_ELEMENTS(labels),
2289 sp_stb_magnitude_value_changed,
2290 1.0, 0 );
2291 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2292 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2293 }
2295 /* Spoke ratio */
2296 {
2297 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
2298 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
2299 eact = create_adjustment_action( "SpokeAction",
2300 _("Spoke ratio"), _("Spoke ratio:"),
2301 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
2302 // Base radius is the same for the closest handle.
2303 _("Base radius to tip radius ratio"),
2304 "/tools/shapes/star/proportion", 0.5,
2305 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2306 0.01, 1.0, 0.01, 0.1,
2307 labels, values, G_N_ELEMENTS(labels),
2308 sp_stb_proportion_value_changed );
2309 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2310 g_object_set_data( holder, "prop_action", eact );
2311 }
2313 if ( !isFlatSided ) {
2314 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2315 } else {
2316 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2317 }
2319 /* Roundedness */
2320 {
2321 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
2322 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
2323 eact = create_adjustment_action( "RoundednessAction",
2324 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
2325 "/tools/shapes/star/rounded", 0.0,
2326 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2327 -10.0, 10.0, 0.01, 0.1,
2328 labels, values, G_N_ELEMENTS(labels),
2329 sp_stb_rounded_value_changed );
2330 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2331 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2332 }
2334 /* Randomization */
2335 {
2336 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
2337 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
2338 eact = create_adjustment_action( "RandomizationAction",
2339 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
2340 "/tools/shapes/star/randomized", 0.0,
2341 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2342 -10.0, 10.0, 0.001, 0.01,
2343 labels, values, G_N_ELEMENTS(labels),
2344 sp_stb_randomized_value_changed, 0.1, 3 );
2345 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2346 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2347 }
2348 }
2350 {
2351 /* Reset */
2352 {
2353 GtkAction* act = gtk_action_new( "StarResetAction",
2354 _("Defaults"),
2355 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2356 GTK_STOCK_CLEAR );
2357 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
2358 gtk_action_group_add_action( mainActions, act );
2359 gtk_action_set_sensitive( act, TRUE );
2360 }
2361 }
2363 sigc::connection *connection = new sigc::connection(
2364 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
2365 );
2366 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2367 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2368 }
2371 //########################
2372 //## Rect ##
2373 //########################
2375 static void sp_rtb_sensitivize( GObject *tbl )
2376 {
2377 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
2378 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
2379 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
2381 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
2382 gtk_action_set_sensitive( not_rounded, FALSE );
2383 } else {
2384 gtk_action_set_sensitive( not_rounded, TRUE );
2385 }
2386 }
2389 static void
2390 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
2391 void (*setter)(SPRect *, gdouble))
2392 {
2393 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2395 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2396 SPUnit const *unit = tracker->getActiveUnit();
2398 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2399 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2400 prefs->setDouble(Glib::ustring("/tools/shapes/rect/") + value_name, sp_units_get_pixels(adj->value, *unit));
2401 }
2403 // quit if run by the attr_changed listener
2404 if (g_object_get_data( tbl, "freeze" )) {
2405 return;
2406 }
2408 // in turn, prevent listener from responding
2409 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2411 bool modmade = false;
2412 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2413 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2414 if (SP_IS_RECT(items->data)) {
2415 if (adj->value != 0) {
2416 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2417 } else {
2418 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2419 }
2420 modmade = true;
2421 }
2422 }
2424 sp_rtb_sensitivize( tbl );
2426 if (modmade) {
2427 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2428 _("Change rectangle"));
2429 }
2431 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2432 }
2434 static void
2435 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2436 {
2437 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2438 }
2440 static void
2441 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2442 {
2443 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2444 }
2446 static void
2447 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2448 {
2449 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2450 }
2452 static void
2453 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2454 {
2455 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2456 }
2460 static void
2461 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2462 {
2463 GtkAdjustment *adj = 0;
2465 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2466 gtk_adjustment_set_value(adj, 0.0);
2467 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2468 gtk_adjustment_value_changed(adj);
2470 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2471 gtk_adjustment_set_value(adj, 0.0);
2472 gtk_adjustment_value_changed(adj);
2474 sp_rtb_sensitivize( obj );
2475 }
2477 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2478 gchar const */*old_value*/, gchar const */*new_value*/,
2479 bool /*is_interactive*/, gpointer data)
2480 {
2481 GObject *tbl = G_OBJECT(data);
2483 // quit if run by the _changed callbacks
2484 if (g_object_get_data( tbl, "freeze" )) {
2485 return;
2486 }
2488 // in turn, prevent callbacks from responding
2489 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2491 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2492 SPUnit const *unit = tracker->getActiveUnit();
2494 gpointer item = g_object_get_data( tbl, "item" );
2495 if (item && SP_IS_RECT(item)) {
2496 {
2497 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2498 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2499 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2500 }
2502 {
2503 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2504 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2505 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2506 }
2508 {
2509 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2510 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2511 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2512 }
2514 {
2515 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2516 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2517 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2518 }
2519 }
2521 sp_rtb_sensitivize( tbl );
2523 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2524 }
2527 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2528 NULL, /* child_added */
2529 NULL, /* child_removed */
2530 rect_tb_event_attr_changed,
2531 NULL, /* content_changed */
2532 NULL /* order_changed */
2533 };
2535 /**
2536 * \param selection should not be NULL.
2537 */
2538 static void
2539 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2540 {
2541 int n_selected = 0;
2542 Inkscape::XML::Node *repr = NULL;
2543 SPItem *item = NULL;
2545 if ( g_object_get_data( tbl, "repr" ) ) {
2546 g_object_set_data( tbl, "item", NULL );
2547 }
2548 purge_repr_listener( tbl, tbl );
2550 for (GSList const *items = selection->itemList();
2551 items != NULL;
2552 items = items->next) {
2553 if (SP_IS_RECT((SPItem *) items->data)) {
2554 n_selected++;
2555 item = (SPItem *) items->data;
2556 repr = SP_OBJECT_REPR(item);
2557 }
2558 }
2560 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2562 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2564 if (n_selected == 0) {
2565 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2567 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2568 gtk_action_set_sensitive(w, FALSE);
2569 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2570 gtk_action_set_sensitive(h, FALSE);
2572 } else if (n_selected == 1) {
2573 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2574 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2576 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2577 gtk_action_set_sensitive(w, TRUE);
2578 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2579 gtk_action_set_sensitive(h, TRUE);
2581 if (repr) {
2582 g_object_set_data( tbl, "repr", repr );
2583 g_object_set_data( tbl, "item", item );
2584 Inkscape::GC::anchor(repr);
2585 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2586 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2587 }
2588 } else {
2589 // FIXME: implement averaging of all parameters for multiple selected
2590 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2591 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2592 sp_rtb_sensitivize( tbl );
2593 }
2594 }
2597 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2598 {
2599 EgeAdjustmentAction* eact = 0;
2600 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
2602 {
2603 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2604 ege_output_action_set_use_markup( act, TRUE );
2605 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2606 g_object_set_data( holder, "mode_action", act );
2607 }
2609 // rx/ry units menu: create
2610 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2611 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2612 // fixme: add % meaning per cent of the width/height
2613 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2614 g_object_set_data( holder, "tracker", tracker );
2616 /* W */
2617 {
2618 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2619 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2620 eact = create_adjustment_action( "RectWidthAction",
2621 _("Width"), _("W:"), _("Width of rectangle"),
2622 "/tools/shapes/rect/width", 0,
2623 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2624 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2625 labels, values, G_N_ELEMENTS(labels),
2626 sp_rtb_width_value_changed );
2627 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2628 g_object_set_data( holder, "width_action", eact );
2629 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2630 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2631 }
2633 /* H */
2634 {
2635 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2636 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2637 eact = create_adjustment_action( "RectHeightAction",
2638 _("Height"), _("H:"), _("Height of rectangle"),
2639 "/tools/shapes/rect/height", 0,
2640 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2641 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2642 labels, values, G_N_ELEMENTS(labels),
2643 sp_rtb_height_value_changed );
2644 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2645 g_object_set_data( holder, "height_action", eact );
2646 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2647 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2648 }
2650 /* rx */
2651 {
2652 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2653 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2654 eact = create_adjustment_action( "RadiusXAction",
2655 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2656 "/tools/shapes/rect/rx", 0,
2657 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2658 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2659 labels, values, G_N_ELEMENTS(labels),
2660 sp_rtb_rx_value_changed);
2661 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2662 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2663 }
2665 /* ry */
2666 {
2667 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2668 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2669 eact = create_adjustment_action( "RadiusYAction",
2670 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2671 "/tools/shapes/rect/ry", 0,
2672 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2673 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2674 labels, values, G_N_ELEMENTS(labels),
2675 sp_rtb_ry_value_changed);
2676 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2677 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2678 }
2680 // add the units menu
2681 {
2682 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2683 gtk_action_group_add_action( mainActions, act );
2684 }
2686 /* Reset */
2687 {
2688 InkAction* inky = ink_action_new( "RectResetAction",
2689 _("Not rounded"),
2690 _("Make corners sharp"),
2691 "squared_corner",
2692 secondarySize );
2693 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2694 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2695 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2696 g_object_set_data( holder, "not_rounded", inky );
2697 }
2699 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2700 sp_rtb_sensitivize( holder );
2702 sigc::connection *connection = new sigc::connection(
2703 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2704 );
2705 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2706 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2707 }
2709 //########################
2710 //## 3D Box ##
2711 //########################
2713 // normalize angle so that it lies in the interval [0,360]
2714 static double box3d_normalize_angle (double a) {
2715 double angle = a + ((int) (a/360.0))*360;
2716 if (angle < 0) {
2717 angle += 360.0;
2718 }
2719 return angle;
2720 }
2722 static void
2723 box3d_set_button_and_adjustment(Persp3D *persp, Proj::Axis axis,
2724 GtkAdjustment *adj, GtkAction *act, GtkToggleAction *tact) {
2725 // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
2726 // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
2727 // are reset).
2728 bool is_infinite = !persp3d_VP_is_finite(persp, axis);
2730 if (is_infinite) {
2731 gtk_toggle_action_set_active(tact, TRUE);
2732 gtk_action_set_sensitive(act, TRUE);
2734 double angle = persp3d_get_infinite_angle(persp, axis);
2735 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
2736 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
2737 }
2738 } else {
2739 gtk_toggle_action_set_active(tact, FALSE);
2740 gtk_action_set_sensitive(act, FALSE);
2741 }
2742 }
2744 static void
2745 box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) {
2746 if (!persp_repr) {
2747 g_print ("No perspective given to box3d_resync_toolbar().\n");
2748 return;
2749 }
2751 GtkWidget *tbl = GTK_WIDGET(data);
2752 GtkAdjustment *adj = 0;
2753 GtkAction *act = 0;
2754 GtkToggleAction *tact = 0;
2755 Persp3D *persp = persp3d_get_from_repr(persp_repr);
2756 {
2757 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
2758 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
2759 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action;
2761 box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact);
2762 }
2763 {
2764 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_y"));
2765 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action"));
2766 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action;
2768 box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact);
2769 }
2770 {
2771 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_z"));
2772 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action"));
2773 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action;
2775 box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact);
2776 }
2777 }
2779 static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2780 gchar const */*old_value*/, gchar const */*new_value*/,
2781 bool /*is_interactive*/, gpointer data)
2782 {
2783 GtkWidget *tbl = GTK_WIDGET(data);
2785 // quit if run by the attr_changed or selection changed listener
2786 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2787 return;
2788 }
2790 // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling
2791 // sp_document_maybe_done() when the document is undo insensitive)
2792 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2794 // TODO: Only update the appropriate part of the toolbar
2795 // if (!strcmp(name, "inkscape:vp_z")) {
2796 box3d_resync_toolbar(repr, G_OBJECT(tbl));
2797 // }
2799 Persp3D *persp = persp3d_get_from_repr(repr);
2800 persp3d_update_box_reprs(persp);
2802 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2803 }
2805 static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
2806 {
2807 NULL, /* child_added */
2808 NULL, /* child_removed */
2809 box3d_persp_tb_event_attr_changed,
2810 NULL, /* content_changed */
2811 NULL /* order_changed */
2812 };
2814 /**
2815 * \param selection Should not be NULL.
2816 */
2817 // FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
2818 // Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
2819 static void
2820 box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2821 {
2822 // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
2823 // disable the angle entry fields for this direction (otherwise entering a value in them should only
2824 // update the perspectives with infinite VPs and leave the other ones untouched).
2826 Inkscape::XML::Node *persp_repr = NULL;
2827 purge_repr_listener(tbl, tbl);
2829 SPItem *item = selection->singleItem();
2830 if (item && SP_IS_BOX3D(item)) {
2831 // FIXME: Also deal with multiple selected boxes
2832 SPBox3D *box = SP_BOX3D(item);
2833 Persp3D *persp = box3d_get_perspective(box);
2834 persp_repr = SP_OBJECT_REPR(persp);
2835 if (persp_repr) {
2836 g_object_set_data(tbl, "repr", persp_repr);
2837 Inkscape::GC::anchor(persp_repr);
2838 sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl);
2839 sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
2840 }
2842 inkscape_active_document()->current_persp3d = persp3d_get_from_repr(persp_repr);
2843 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2844 prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id"));
2846 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
2847 box3d_resync_toolbar(persp_repr, tbl);
2848 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE));
2849 }
2850 }
2852 static void
2853 box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis)
2854 {
2855 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2856 SPDocument *document = sp_desktop_document(desktop);
2858 // quit if run by the attr_changed or selection changed listener
2859 if (g_object_get_data( dataKludge, "freeze" )) {
2860 return;
2861 }
2863 // in turn, prevent listener from responding
2864 g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE));
2866 //Persp3D *persp = document->current_persp3d;
2867 std::list<Persp3D *> sel_persps = sp_desktop_selection(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 persp->tmat.set_infinite_direction (axis, adj->value);
2875 SP_OBJECT(persp)->updateRepr();
2877 // TODO: use the correct axis here, too
2878 sp_document_maybe_done(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)"));
2880 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2881 }
2884 static void
2885 box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2886 {
2887 box3d_angle_value_changed(adj, dataKludge, Proj::X);
2888 }
2890 static void
2891 box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2892 {
2893 box3d_angle_value_changed(adj, dataKludge, Proj::Y);
2894 }
2896 static void
2897 box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2898 {
2899 box3d_angle_value_changed(adj, dataKludge, Proj::Z);
2900 }
2903 static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction */*box3d_angle*/, Proj::Axis axis )
2904 {
2905 // TODO: Take all selected perspectives into account
2906 std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList();
2907 if (sel_persps.empty()) {
2908 // this can happen when the document is created; we silently ignore it
2909 return;
2910 }
2911 Persp3D *persp = sel_persps.front();
2913 bool set_infinite = gtk_toggle_action_get_active(act);
2914 persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
2915 }
2917 static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2918 {
2919 box3d_vp_state_changed(act, box3d_angle, Proj::X);
2920 }
2922 static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2923 {
2924 box3d_vp_state_changed(act, box3d_angle, Proj::Y);
2925 }
2927 static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2928 {
2929 box3d_vp_state_changed(act, box3d_angle, Proj::Z);
2930 }
2932 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2933 {
2934 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2935 EgeAdjustmentAction* eact = 0;
2936 SPDocument *document = sp_desktop_document (desktop);
2937 Persp3D *persp = document->current_persp3d;
2939 EgeAdjustmentAction* box3d_angle_x = 0;
2940 EgeAdjustmentAction* box3d_angle_y = 0;
2941 EgeAdjustmentAction* box3d_angle_z = 0;
2943 /* Angle X */
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( "3DBoxAngleXAction",
2948 _("Angle in X direction"), _("Angle X:"),
2949 // Translators: PL is short for 'perspective line'
2950 _("Angle of PLs in X direction"),
2951 "/tools/shapes/3dbox/box3d_angle_x", 30,
2952 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
2953 -360.0, 360.0, 1.0, 10.0,
2954 labels, values, G_N_ELEMENTS(labels),
2955 box3d_angle_x_value_changed );
2956 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2957 g_object_set_data( holder, "box3d_angle_x_action", eact );
2958 box3d_angle_x = eact;
2959 }
2961 if (!persp3d_VP_is_finite(persp, Proj::X)) {
2962 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2963 } else {
2964 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2965 }
2968 /* VP X state */
2969 {
2970 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction",
2971 // Translators: VP is short for 'vanishing point'
2972 _("State of VP in X direction"),
2973 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2974 "toggle_vp_x",
2975 Inkscape::ICON_SIZE_DECORATION );
2976 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2977 g_object_set_data( holder, "box3d_vp_x_state_action", act );
2978 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x );
2979 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) );
2980 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) );
2981 }
2983 /* Angle Y */
2984 {
2985 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2986 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2987 eact = create_adjustment_action( "3DBoxAngleYAction",
2988 _("Angle in Y direction"), _("Angle Y:"),
2989 // Translators: PL is short for 'perspective line'
2990 _("Angle of PLs in Y direction"),
2991 "/tools/shapes/3dbox/box3d_angle_y", 30,
2992 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2993 -360.0, 360.0, 1.0, 10.0,
2994 labels, values, G_N_ELEMENTS(labels),
2995 box3d_angle_y_value_changed );
2996 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2997 g_object_set_data( holder, "box3d_angle_y_action", eact );
2998 box3d_angle_y = eact;
2999 }
3001 if (!persp3d_VP_is_finite(persp, Proj::Y)) {
3002 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3003 } else {
3004 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3005 }
3007 /* VP Y state */
3008 {
3009 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction",
3010 // Translators: VP is short for 'vanishing point'
3011 _("State of VP in Y direction"),
3012 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
3013 "toggle_vp_y",
3014 Inkscape::ICON_SIZE_DECORATION );
3015 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3016 g_object_set_data( holder, "box3d_vp_y_state_action", act );
3017 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y );
3018 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) );
3019 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) );
3020 }
3022 /* Angle Z */
3023 {
3024 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
3025 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3026 eact = create_adjustment_action( "3DBoxAngleZAction",
3027 _("Angle in Z direction"), _("Angle Z:"),
3028 // Translators: PL is short for 'perspective line'
3029 _("Angle of PLs in Z direction"),
3030 "/tools/shapes/3dbox/box3d_angle_z", 30,
3031 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3032 -360.0, 360.0, 1.0, 10.0,
3033 labels, values, G_N_ELEMENTS(labels),
3034 box3d_angle_z_value_changed );
3035 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3036 g_object_set_data( holder, "box3d_angle_z_action", eact );
3037 box3d_angle_z = eact;
3038 }
3040 if (!persp3d_VP_is_finite(persp, Proj::Z)) {
3041 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3042 } else {
3043 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3044 }
3046 /* VP Z state */
3047 {
3048 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction",
3049 // Translators: VP is short for 'vanishing point'
3050 _("State of VP in Z direction"),
3051 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
3052 "toggle_vp_z",
3053 Inkscape::ICON_SIZE_DECORATION );
3054 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3055 g_object_set_data( holder, "box3d_vp_z_state_action", act );
3056 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z );
3057 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) );
3058 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) );
3059 }
3061 sigc::connection *connection = new sigc::connection(
3062 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
3063 );
3064 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
3065 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
3066 }
3068 //########################
3069 //## Spiral ##
3070 //########################
3072 static void
3073 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustring const &value_name)
3074 {
3075 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3077 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3078 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3079 prefs->setDouble("/tools/shapes/spiral/" + value_name, adj->value);
3080 }
3082 // quit if run by the attr_changed listener
3083 if (g_object_get_data( tbl, "freeze" )) {
3084 return;
3085 }
3087 // in turn, prevent listener from responding
3088 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3090 gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL);
3092 bool modmade = false;
3093 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3094 items != NULL;
3095 items = items->next)
3096 {
3097 if (SP_IS_SPIRAL((SPItem *) items->data)) {
3098 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3099 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
3100 SP_OBJECT((SPItem *) items->data)->updateRepr();
3101 modmade = true;
3102 }
3103 }
3105 g_free(namespaced_name);
3107 if (modmade) {
3108 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
3109 _("Change spiral"));
3110 }
3112 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3113 }
3115 static void
3116 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
3117 {
3118 sp_spl_tb_value_changed(adj, tbl, "revolution");
3119 }
3121 static void
3122 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
3123 {
3124 sp_spl_tb_value_changed(adj, tbl, "expansion");
3125 }
3127 static void
3128 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
3129 {
3130 sp_spl_tb_value_changed(adj, tbl, "t0");
3131 }
3133 static void
3134 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
3135 {
3136 GtkWidget *tbl = GTK_WIDGET(obj);
3138 GtkAdjustment *adj;
3140 // fixme: make settable
3141 gdouble rev = 5;
3142 gdouble exp = 1.0;
3143 gdouble t0 = 0.0;
3145 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
3146 gtk_adjustment_set_value(adj, rev);
3147 gtk_adjustment_value_changed(adj);
3149 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
3150 gtk_adjustment_set_value(adj, exp);
3151 gtk_adjustment_value_changed(adj);
3153 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
3154 gtk_adjustment_set_value(adj, t0);
3155 gtk_adjustment_value_changed(adj);
3157 spinbutton_defocus(GTK_OBJECT(tbl));
3158 }
3161 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3162 gchar const */*old_value*/, gchar const */*new_value*/,
3163 bool /*is_interactive*/, gpointer data)
3164 {
3165 GtkWidget *tbl = GTK_WIDGET(data);
3167 // quit if run by the _changed callbacks
3168 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3169 return;
3170 }
3172 // in turn, prevent callbacks from responding
3173 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3175 GtkAdjustment *adj;
3176 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
3177 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
3179 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
3180 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
3182 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
3183 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
3185 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3186 }
3189 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
3190 NULL, /* child_added */
3191 NULL, /* child_removed */
3192 spiral_tb_event_attr_changed,
3193 NULL, /* content_changed */
3194 NULL /* order_changed */
3195 };
3197 static void
3198 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3199 {
3200 int n_selected = 0;
3201 Inkscape::XML::Node *repr = NULL;
3203 purge_repr_listener( tbl, tbl );
3205 for (GSList const *items = selection->itemList();
3206 items != NULL;
3207 items = items->next)
3208 {
3209 if (SP_IS_SPIRAL((SPItem *) items->data)) {
3210 n_selected++;
3211 repr = SP_OBJECT_REPR((SPItem *) items->data);
3212 }
3213 }
3215 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3217 if (n_selected == 0) {
3218 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3219 } else if (n_selected == 1) {
3220 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3222 if (repr) {
3223 g_object_set_data( tbl, "repr", repr );
3224 Inkscape::GC::anchor(repr);
3225 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
3226 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
3227 }
3228 } else {
3229 // FIXME: implement averaging of all parameters for multiple selected
3230 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3231 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3232 }
3233 }
3236 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3237 {
3238 EgeAdjustmentAction* eact = 0;
3239 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
3241 {
3242 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
3243 ege_output_action_set_use_markup( act, TRUE );
3244 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3245 g_object_set_data( holder, "mode_action", act );
3246 }
3248 /* Revolution */
3249 {
3250 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
3251 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
3252 eact = create_adjustment_action( "SpiralRevolutionAction",
3253 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
3254 "/tools/shapes/spiral/revolution", 3.0,
3255 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
3256 0.01, 1024.0, 0.1, 1.0,
3257 labels, values, G_N_ELEMENTS(labels),
3258 sp_spl_tb_revolution_value_changed, 1, 2);
3259 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3260 }
3262 /* Expansion */
3263 {
3264 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
3265 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
3266 eact = create_adjustment_action( "SpiralExpansionAction",
3267 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
3268 "/tools/shapes/spiral/expansion", 1.0,
3269 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3270 0.0, 1000.0, 0.01, 1.0,
3271 labels, values, G_N_ELEMENTS(labels),
3272 sp_spl_tb_expansion_value_changed);
3273 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3274 }
3276 /* T0 */
3277 {
3278 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
3279 gdouble values[] = {0, 0.5, 0.9};
3280 eact = create_adjustment_action( "SpiralT0Action",
3281 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
3282 "/tools/shapes/spiral/t0", 0.0,
3283 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3284 0.0, 0.999, 0.01, 1.0,
3285 labels, values, G_N_ELEMENTS(labels),
3286 sp_spl_tb_t0_value_changed);
3287 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3288 }
3290 /* Reset */
3291 {
3292 InkAction* inky = ink_action_new( "SpiralResetAction",
3293 _("Defaults"),
3294 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
3295 GTK_STOCK_CLEAR,
3296 secondarySize );
3297 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
3298 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3299 }
3302 sigc::connection *connection = new sigc::connection(
3303 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
3304 );
3305 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3306 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3307 }
3309 //########################
3310 //## Pen/Pencil ##
3311 //########################
3313 /* This is used in generic functions below to share large portions of code between pen and pencil tool */
3314 static Glib::ustring const
3315 freehand_tool_name(GObject *dataKludge)
3316 {
3317 SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
3318 return ( tools_isactive(desktop, TOOLS_FREEHAND_PEN)
3319 ? "/tools/freehand/pen"
3320 : "/tools/freehand/pencil" );
3321 }
3323 static void freehand_mode_changed(EgeSelectOneAction* act, GObject* tbl)
3324 {
3325 gint mode = ege_select_one_action_get_active(act);
3327 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3328 prefs->setInt(freehand_tool_name(tbl) + "/freehand-mode", mode);
3330 SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop");
3332 // in pen tool we have more options than in pencil tool; if one of them was chosen, we do any
3333 // preparatory work here
3334 if (SP_IS_PEN_CONTEXT(desktop->event_context)) {
3335 SPPenContext *pc = SP_PEN_CONTEXT(desktop->event_context);
3336 sp_pen_context_set_polyline_mode(pc);
3337 }
3338 }
3340 static void sp_add_freehand_mode_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil)
3341 {
3342 /* Freehand mode toggle buttons */
3343 {
3344 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3345 guint freehandMode = prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/freehand-mode" : "/tools/freehand/pen/freehand-mode" ), 0);
3346 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
3348 {
3349 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3351 GtkTreeIter iter;
3352 gtk_list_store_append( model, &iter );
3353 gtk_list_store_set( model, &iter,
3354 0, _("Bezier"),
3355 1, _("Create regular Bezier path"),
3356 2, "bezier_mode",
3357 -1 );
3359 gtk_list_store_append( model, &iter );
3360 gtk_list_store_set( model, &iter,
3361 0, _("Spiro"),
3362 1, _("Create Spiro path"),
3363 2, "spiro_splines_mode",
3364 -1 );
3366 if (!tool_is_pencil) {
3367 gtk_list_store_append( model, &iter );
3368 gtk_list_store_set( model, &iter,
3369 0, _("Zigzag"),
3370 1, _("Create a sequence of straight line segments"),
3371 2, "polylines_mode",
3372 -1 );
3374 gtk_list_store_append( model, &iter );
3375 gtk_list_store_set( model, &iter,
3376 0, _("Paraxial"),
3377 1, _("Create a sequence of paraxial line segments"),
3378 2, "paraxial_lines_mode",
3379 -1 );
3380 }
3382 EgeSelectOneAction* act = ege_select_one_action_new(tool_is_pencil ?
3383 "FreehandModeActionPencil" :
3384 "FreehandModeActionPen",
3385 (_("Mode:")), ("Mode"), NULL, GTK_TREE_MODEL(model) );
3386 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3388 ege_select_one_action_set_appearance( act, "full" );
3389 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3390 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3391 ege_select_one_action_set_icon_column( act, 2 );
3392 ege_select_one_action_set_icon_size( act, secondarySize );
3393 ege_select_one_action_set_tooltip_column( act, 1 );
3395 ege_select_one_action_set_active( act, freehandMode);
3396 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(freehand_mode_changed), holder);
3397 }
3398 }
3399 }
3401 static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge) {
3402 gint shape = ege_select_one_action_get_active( act );
3403 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3404 prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape);
3405 }
3407 /**
3408 * \brief Generate the list of freehand advanced shape option entries.
3409 */
3410 GList * freehand_shape_dropdown_items_list() {
3411 GList *glist = NULL;
3413 glist = g_list_append (glist, _("None"));
3414 glist = g_list_append (glist, _("Triangle in"));
3415 glist = g_list_append (glist, _("Triangle out"));
3416 glist = g_list_append (glist, _("Ellipse"));
3417 glist = g_list_append (glist, _("From clipboard"));
3419 return glist;
3420 }
3422 static void
3423 freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) {
3424 /*advanced shape options */
3425 {
3426 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3427 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
3429 GList* items = 0;
3430 gint count = 0;
3431 for ( items = freehand_shape_dropdown_items_list(); items ; items = g_list_next(items) )
3432 {
3433 GtkTreeIter iter;
3434 gtk_list_store_append( model, &iter );
3435 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
3436 count++;
3437 }
3438 g_list_free( items );
3439 items = 0;
3440 EgeSelectOneAction* act1 = ege_select_one_action_new(
3441 tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction",
3442 _("Shape:"), ("Shape"), NULL, GTK_TREE_MODEL(model));
3443 g_object_set( act1, "short_label", _("Shape:"), NULL );
3444 ege_select_one_action_set_appearance( act1, "compact" );
3445 ege_select_one_action_set_active( act1, prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/shape" : "/tools/freehand/pen/shape" ), 0) );
3446 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(freehand_change_shape), holder );
3447 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
3448 g_object_set_data( holder, "shape_action", act1 );
3449 }
3450 }
3452 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3453 {
3454 sp_add_freehand_mode_toggle(mainActions, holder, false);
3455 freehand_add_advanced_shape_options(mainActions, holder, false);
3456 }
3459 static void
3460 sp_pencil_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
3461 {
3462 GtkWidget *tbl = GTK_WIDGET(obj);
3464 GtkAdjustment *adj;
3466 // fixme: make settable
3467 gdouble tolerance = 4;
3469 adj = (GtkAdjustment*)gtk_object_get_data(obj, "tolerance");
3470 gtk_adjustment_set_value(adj, tolerance);
3471 gtk_adjustment_value_changed(adj);
3473 spinbutton_defocus(GTK_OBJECT(tbl));
3474 }
3476 static void
3477 sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl)
3478 {
3479 // quit if run by the attr_changed listener
3480 if (g_object_get_data( tbl, "freeze" )) {
3481 return;
3482 }
3483 // in turn, prevent listener from responding
3484 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3485 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3486 prefs->setDouble("/tools/freehand/pencil/tolerance", adj->value);
3487 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3488 }
3490 class PencilToleranceObserver : public Inkscape::Preferences::Observer {
3491 public:
3492 PencilToleranceObserver(Glib::ustring const &path, GObject *x) : Observer(path), _obj(x)
3493 {
3494 g_object_set_data(_obj, "prefobserver", this);
3495 }
3496 virtual ~PencilToleranceObserver() {
3497 if (g_object_get_data(_obj, "prefobserver") == this) {
3498 g_object_set_data(_obj, "prefobserver", NULL);
3499 }
3500 }
3501 virtual void notify(Inkscape::Preferences::Entry const &val) {
3502 GObject* tbl = _obj;
3503 if (g_object_get_data( tbl, "freeze" )) {
3504 return;
3505 }
3506 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3508 GtkAdjustment * adj = (GtkAdjustment*)g_object_get_data(tbl, "tolerance");
3510 double v = val.getDouble(adj->value);
3511 gtk_adjustment_set_value(adj, v);
3512 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3513 }
3514 private:
3515 GObject *_obj;
3516 };
3519 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3520 {
3521 sp_add_freehand_mode_toggle(mainActions, holder, true);
3523 EgeAdjustmentAction* eact = 0;
3525 /* Tolerance */
3526 {
3527 gchar const* labels[] = {_("(many nodes, rough)"), _("(default)"), 0, 0, 0, 0, _("(few nodes, smooth)")};
3528 gdouble values[] = {1, 10, 20, 30, 50, 75, 100};
3529 eact = create_adjustment_action( "PencilToleranceAction",
3530 _("Smoothing:"), _("Smoothing: "),
3531 _("How much smoothing (simplifying) is applied to the line"),
3532 "/tools/freehand/pencil/tolerance",
3533 3.0,
3534 GTK_WIDGET(desktop->canvas), NULL,
3535 holder, TRUE, "altx-pencil",
3536 1, 100.0, 0.5, 0,
3537 labels, values, G_N_ELEMENTS(labels),
3538 sp_pencil_tb_tolerance_value_changed,
3539 1, 2);
3540 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3541 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3543 PencilToleranceObserver *obs =
3544 new PencilToleranceObserver("/tools/freehand/pencil/tolerance", G_OBJECT(holder));
3545 }
3547 /* advanced shape options */
3548 freehand_add_advanced_shape_options(mainActions, holder, true);
3550 /* Reset */
3551 {
3552 InkAction* inky = ink_action_new( "PencilResetAction",
3553 _("Defaults"),
3554 _("Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
3555 GTK_STOCK_CLEAR,
3556 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3557 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder );
3558 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3559 }
3561 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3563 }
3566 //########################
3567 //## Tweak ##
3568 //########################
3570 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3571 {
3572 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3573 prefs->setDouble( "/tools/tweak/width", adj->value * 0.01 );
3574 }
3576 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3577 {
3578 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3579 prefs->setDouble( "/tools/tweak/force", adj->value * 0.01 );
3580 }
3582 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3583 {
3584 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3585 prefs->setBool("/tools/tweak/usepressure", gtk_toggle_action_get_active(act));
3586 }
3588 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
3589 {
3590 int mode = ege_select_one_action_get_active( act );
3591 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3592 prefs->setInt("/tools/tweak/mode", mode);
3594 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
3595 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
3596 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
3597 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
3598 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
3599 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
3600 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
3601 if (doh) gtk_action_set_sensitive (doh, TRUE);
3602 if (dos) gtk_action_set_sensitive (dos, TRUE);
3603 if (dol) gtk_action_set_sensitive (dol, TRUE);
3604 if (doo) gtk_action_set_sensitive (doo, TRUE);
3605 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
3606 if (fid) gtk_action_set_sensitive (fid, FALSE);
3607 } else {
3608 if (doh) gtk_action_set_sensitive (doh, FALSE);
3609 if (dos) gtk_action_set_sensitive (dos, FALSE);
3610 if (dol) gtk_action_set_sensitive (dol, FALSE);
3611 if (doo) gtk_action_set_sensitive (doo, FALSE);
3612 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
3613 if (fid) gtk_action_set_sensitive (fid, TRUE);
3614 }
3615 }
3617 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3618 {
3619 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3620 prefs->setDouble( "/tools/tweak/fidelity", adj->value * 0.01 );
3621 }
3623 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
3624 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3625 prefs->setBool("/tools/tweak/doh", gtk_toggle_action_get_active(act));
3626 }
3627 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
3628 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3629 prefs->setBool("/tools/tweak/dos", gtk_toggle_action_get_active(act));
3630 }
3631 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
3632 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3633 prefs->setBool("/tools/tweak/dol", gtk_toggle_action_get_active(act));
3634 }
3635 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
3636 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3637 prefs->setBool("/tools/tweak/doo", gtk_toggle_action_get_active(act));
3638 }
3640 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3641 {
3642 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
3643 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3645 {
3646 /* Width */
3647 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
3648 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3649 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
3650 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
3651 "/tools/tweak/width", 15,
3652 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
3653 1, 100, 1.0, 0.0,
3654 labels, values, G_N_ELEMENTS(labels),
3655 sp_tweak_width_value_changed, 0.01, 0, 100 );
3656 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3657 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3658 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3659 }
3662 {
3663 /* Force */
3664 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
3665 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
3666 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
3667 _("Force"), _("Force:"), _("The force of the tweak action"),
3668 "/tools/tweak/force", 20,
3669 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
3670 1, 100, 1.0, 0.0,
3671 labels, values, G_N_ELEMENTS(labels),
3672 sp_tweak_force_value_changed, 0.01, 0, 100 );
3673 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
3674 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3675 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3676 }
3678 /* Mode */
3679 {
3680 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3682 GtkTreeIter iter;
3683 gtk_list_store_append( model, &iter );
3684 gtk_list_store_set( model, &iter,
3685 0, _("Move mode"),
3686 1, _("Move objects in any direction"),
3687 2, "tweak_move_mode",
3688 -1 );
3690 gtk_list_store_append( model, &iter );
3691 gtk_list_store_set( model, &iter,
3692 0, _("Move in/out mode"),
3693 1, _("Move objects towards cursor; with Shift from cursor"),
3694 2, "tweak_move_mode_inout",
3695 -1 );
3697 gtk_list_store_append( model, &iter );
3698 gtk_list_store_set( model, &iter,
3699 0, _("Move jitter mode"),
3700 1, _("Move objects in random directions"),
3701 2, "tweak_move_mode_jitter",
3702 -1 );
3704 gtk_list_store_append( model, &iter );
3705 gtk_list_store_set( model, &iter,
3706 0, _("Scale mode"),
3707 1, _("Scale objects, with Shift scale up"),
3708 2, "tweak_scale_mode",
3709 -1 );
3711 gtk_list_store_append( model, &iter );
3712 gtk_list_store_set( model, &iter,
3713 0, _("Rotate mode"),
3714 1, _("Rotate objects, with Shift counterclockwise"),
3715 2, "tweak_rotate_mode",
3716 -1 );
3718 gtk_list_store_append( model, &iter );
3719 gtk_list_store_set( model, &iter,
3720 0, _("Duplicate/delete mode"),
3721 1, _("Duplicate objects, with Shift delete"),
3722 2, "tweak_moreless_mode",
3723 -1 );
3725 gtk_list_store_append( model, &iter );
3726 gtk_list_store_set( model, &iter,
3727 0, _("Push mode"),
3728 1, _("Push parts of paths in any direction"),
3729 2, "tweak_push_mode",
3730 -1 );
3732 gtk_list_store_append( model, &iter );
3733 gtk_list_store_set( model, &iter,
3734 0, _("Shrink/grow mode"),
3735 1, _("Shrink (inset) parts of paths; with Shift grow (outset)"),
3736 2, "tweak_shrink_mode",
3737 -1 );
3739 gtk_list_store_append( model, &iter );
3740 gtk_list_store_set( model, &iter,
3741 0, _("Attract/repel mode"),
3742 1, _("Attract parts of paths towards cursor; with Shift from cursor"),
3743 2, "tweak_attract_mode",
3744 -1 );
3746 gtk_list_store_append( model, &iter );
3747 gtk_list_store_set( model, &iter,
3748 0, _("Roughen mode"),
3749 1, _("Roughen parts of paths"),
3750 2, "tweak_roughen_mode",
3751 -1 );
3753 gtk_list_store_append( model, &iter );
3754 gtk_list_store_set( model, &iter,
3755 0, _("Color paint mode"),
3756 1, _("Paint the tool's color upon selected objects"),
3757 2, "tweak_colorpaint_mode",
3758 -1 );
3760 gtk_list_store_append( model, &iter );
3761 gtk_list_store_set( model, &iter,
3762 0, _("Color jitter mode"),
3763 1, _("Jitter the colors of selected objects"),
3764 2, "tweak_colorjitter_mode",
3765 -1 );
3767 gtk_list_store_append( model, &iter );
3768 gtk_list_store_set( model, &iter,
3769 0, _("Blur mode"),
3770 1, _("Blur selected objects more; with Shift, blur less"),
3771 2, "tweak_blur_mode",
3772 -1 );
3775 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
3776 g_object_set( act, "short_label", _("Mode:"), NULL );
3777 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3778 g_object_set_data( holder, "mode_action", act );
3780 ege_select_one_action_set_appearance( act, "full" );
3781 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3782 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3783 ege_select_one_action_set_icon_column( act, 2 );
3784 ege_select_one_action_set_icon_size( act, secondarySize );
3785 ege_select_one_action_set_tooltip_column( act, 1 );
3787 gint mode = prefs->getInt("/tools/tweak/mode", 0);
3788 ege_select_one_action_set_active( act, mode );
3789 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3791 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3792 }
3794 guint mode = prefs->getInt("/tools/tweak/mode", 0);
3796 {
3797 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3798 ege_output_action_set_use_markup( act, TRUE );
3799 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3800 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3801 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3802 g_object_set_data( holder, "tweak_channels_label", act);
3803 }
3805 {
3806 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3807 _("Hue"),
3808 _("In color mode, act on objects' hue"),
3809 NULL,
3810 Inkscape::ICON_SIZE_DECORATION );
3811 //TRANSLATORS: "H" here stands for hue
3812 g_object_set( act, "short_label", _("H"), NULL );
3813 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3814 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3815 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doh", true) );
3816 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3817 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3818 g_object_set_data( holder, "tweak_doh", act);
3819 }
3820 {
3821 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3822 _("Saturation"),
3823 _("In color mode, act on objects' saturation"),
3824 NULL,
3825 Inkscape::ICON_SIZE_DECORATION );
3826 //TRANSLATORS: "S" here stands for Saturation
3827 g_object_set( act, "short_label", _("S"), NULL );
3828 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3829 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3830 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dos", true) );
3831 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3832 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3833 g_object_set_data( holder, "tweak_dos", act );
3834 }
3835 {
3836 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3837 _("Lightness"),
3838 _("In color mode, act on objects' lightness"),
3839 NULL,
3840 Inkscape::ICON_SIZE_DECORATION );
3841 //TRANSLATORS: "L" here stands for Lightness
3842 g_object_set( act, "short_label", _("L"), NULL );
3843 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3844 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3845 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dol", true) );
3846 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3847 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3848 g_object_set_data( holder, "tweak_dol", act );
3849 }
3850 {
3851 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3852 _("Opacity"),
3853 _("In color mode, act on objects' opacity"),
3854 NULL,
3855 Inkscape::ICON_SIZE_DECORATION );
3856 //TRANSLATORS: "O" here stands for Opacity
3857 g_object_set( act, "short_label", _("O"), NULL );
3858 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3859 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3860 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doo", true) );
3861 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3862 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3863 g_object_set_data( holder, "tweak_doo", act );
3864 }
3866 { /* Fidelity */
3867 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3868 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3869 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3870 _("Fidelity"), _("Fidelity:"),
3871 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3872 "/tools/tweak/fidelity", 50,
3873 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3874 1, 100, 1.0, 10.0,
3875 labels, values, G_N_ELEMENTS(labels),
3876 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3877 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3878 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3879 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3880 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3881 g_object_set_data( holder, "tweak_fidelity", eact );
3882 }
3885 /* Use Pressure button */
3886 {
3887 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3888 _("Pressure"),
3889 _("Use the pressure of the input device to alter the force of tweak action"),
3890 "use_pressure",
3891 Inkscape::ICON_SIZE_DECORATION );
3892 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3893 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3894 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/usepressure", true) );
3895 }
3897 }
3900 //########################
3901 //## Calligraphy ##
3902 //########################
3903 static void update_presets_list (GObject *tbl)
3904 {
3905 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3906 if (g_object_get_data(tbl, "presets_blocked"))
3907 return;
3909 EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
3910 if (!sel) {
3911 // WTF!? This will cause a segfault if ever reached
3912 //ege_select_one_action_set_active(sel, 0);
3913 return;
3914 }
3916 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
3918 int ege_index = 1;
3919 for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++ege_index) {
3920 bool match = true;
3922 std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(*i);
3923 for (std::vector<Inkscape::Preferences::Entry>::iterator j = preset.begin(); j != preset.end(); ++j) {
3924 Glib::ustring entry_name = j->getEntryName();
3925 if (entry_name == "id" || entry_name == "name") continue;
3927 void *widget = g_object_get_data(tbl, entry_name.data());
3928 if (widget) {
3929 if (GTK_IS_ADJUSTMENT(widget)) {
3930 double v = j->getDouble();
3931 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
3932 //std::cout << "compared adj " << attr_name << gtk_adjustment_get_value(adj) << " to " << v << "\n";
3933 if (fabs(gtk_adjustment_get_value(adj) - v) > 1e-6) {
3934 match = false;
3935 break;
3936 }
3937 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
3938 bool v = j->getBool();
3939 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
3940 //std::cout << "compared toggle " << attr_name << gtk_toggle_action_get_active(toggle) << " to " << v << "\n";
3941 if ( static_cast<bool>(gtk_toggle_action_get_active(toggle)) != v ) {
3942 match = false;
3943 break;
3944 }
3945 }
3946 }
3947 }
3949 if (match) {
3950 // newly added item is at the same index as the
3951 // save command, so we need to change twice for it to take effect
3952 ege_select_one_action_set_active(sel, 0);
3953 ege_select_one_action_set_active(sel, ege_index); // one-based index
3954 return;
3955 }
3956 }
3958 // no match found
3959 ege_select_one_action_set_active(sel, 0);
3960 }
3962 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
3963 {
3964 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3965 prefs->setDouble( "/tools/calligraphic/mass", adj->value * 0.01 );
3966 update_presets_list(tbl);
3967 }
3969 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
3970 {
3971 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3972 prefs->setDouble( "/tools/calligraphic/wiggle", adj->value * 0.01 );
3973 update_presets_list(tbl);
3974 }
3976 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
3977 {
3978 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3979 prefs->setDouble( "/tools/calligraphic/angle", adj->value );
3980 update_presets_list(tbl);
3981 }
3983 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
3984 {
3985 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3986 prefs->setDouble( "/tools/calligraphic/width", adj->value * 0.01 );
3987 update_presets_list(tbl);
3988 }
3990 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
3991 {
3992 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3993 prefs->setDouble("/tools/calligraphic/thinning", adj->value * 0.01 );
3994 update_presets_list(tbl);
3995 }
3997 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
3998 {
3999 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4000 prefs->setDouble( "/tools/calligraphic/flatness", adj->value * 0.01);
4001 update_presets_list(tbl);
4002 }
4004 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
4005 {
4006 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4007 prefs->setDouble( "/tools/calligraphic/tremor", adj->value * 0.01 );
4008 update_presets_list(tbl);
4009 }
4011 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
4012 {
4013 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4014 prefs->setDouble( "/tools/calligraphic/cap_rounding", adj->value );
4015 update_presets_list(tbl);
4016 }
4018 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, GObject* tbl )
4019 {
4020 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4021 prefs->setBool("/tools/calligraphic/usepressure", gtk_toggle_action_get_active( act ));
4022 update_presets_list(tbl);
4023 }
4025 static void sp_ddc_trace_background_changed( GtkToggleAction *act, GObject* tbl )
4026 {
4027 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4028 prefs->setBool("/tools/calligraphic/tracebackground", gtk_toggle_action_get_active( act ));
4029 update_presets_list(tbl);
4030 }
4032 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject* tbl )
4033 {
4034 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4035 GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle_action"));
4036 prefs->setBool("/tools/calligraphic/usetilt", gtk_toggle_action_get_active( act ));
4037 update_presets_list(tbl);
4038 if (calligraphy_angle )
4039 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
4040 }
4043 static gchar const *const widget_names[] = {
4044 "width",
4045 "mass",
4046 "wiggle",
4047 "angle",
4048 "thinning",
4049 "tremor",
4050 "flatness",
4051 "cap_rounding",
4052 "usepressure",
4053 "tracebackground",
4054 "usetilt"
4055 };
4058 static void sp_dcc_build_presets_list(GObject *tbl)
4059 {
4060 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE));
4062 EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
4063 GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
4064 gtk_list_store_clear (model);
4066 {
4067 GtkTreeIter iter;
4068 gtk_list_store_append( model, &iter );
4069 gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 );
4070 }
4072 // iterate over all presets to populate the list
4073 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4074 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
4075 int ii=1;
4077 for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i) {
4078 GtkTreeIter iter;
4079 Glib::ustring preset_name = prefs->getString(*i + "/name");
4080 gtk_list_store_append( model, &iter );
4081 gtk_list_store_set( model, &iter, 0, preset_name.data(), 1, ii++, -1 );
4082 }
4084 {
4085 GtkTreeIter iter;
4086 gtk_list_store_append( model, &iter );
4087 gtk_list_store_set( model, &iter, 0, _("Save..."), 1, ii, -1 );
4088 g_object_set_data(tbl, "save_presets_index", GINT_TO_POINTER(ii));
4089 }
4091 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
4093 update_presets_list (tbl);
4094 }
4096 static void sp_dcc_save_profile (GtkWidget */*widget*/, GObject *tbl)
4097 {
4098 using Inkscape::UI::Dialog::CalligraphicProfileRename;
4099 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4100 SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop" );
4101 if (! desktop) return;
4103 if (g_object_get_data(tbl, "presets_blocked"))
4104 return;
4106 CalligraphicProfileRename::show(desktop);
4107 if ( !CalligraphicProfileRename::applied()) {
4108 // dialog cancelled
4109 update_presets_list (tbl);
4110 return;
4111 }
4112 Glib::ustring profile_name = CalligraphicProfileRename::getProfileName();
4114 if (profile_name.empty()) {
4115 // empty name entered
4116 update_presets_list (tbl);
4117 return;
4118 }
4120 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE));
4122 // If there's a preset with the given name, find it and set save_path appropriately
4123 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
4124 int total_presets = presets.size();
4125 int new_index = -1;
4126 Glib::ustring save_path; // profile pref path without a trailing slash
4128 int temp_index = 0;
4129 for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++temp_index) {
4130 Glib::ustring name = prefs->getString(*i + "/name");
4131 if (!name.empty() && profile_name == name) {
4132 new_index = temp_index;
4133 save_path = *i;
4134 break;
4135 }
4136 }
4138 if (new_index == -1) {
4139 // no preset with this name, create
4140 new_index = total_presets + 1;
4141 gchar *profile_id = g_strdup_printf("/dcc%d", new_index);
4142 save_path = Glib::ustring("/tools/calligraphic/preset") + profile_id;
4143 g_free(profile_id);
4144 }
4146 for (unsigned i = 0; i < G_N_ELEMENTS(widget_names); ++i) {
4147 gchar const *const widget_name = widget_names[i];
4148 void *widget = g_object_get_data(tbl, widget_name);
4149 if (widget) {
4150 if (GTK_IS_ADJUSTMENT(widget)) {
4151 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
4152 prefs->setDouble(save_path + "/" + widget_name, gtk_adjustment_get_value(adj));
4153 //std::cout << "wrote adj " << widget_name << ": " << v << "\n";
4154 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
4155 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
4156 prefs->setBool(save_path + "/" + widget_name, gtk_toggle_action_get_active(toggle));
4157 //std::cout << "wrote tog " << widget_name << ": " << v << "\n";
4158 } else {
4159 g_warning("Unknown widget type for preset: %s\n", widget_name);
4160 }
4161 } else {
4162 g_warning("Bad key when writing preset: %s\n", widget_name);
4163 }
4164 }
4165 prefs->setString(save_path + "/name", profile_name);
4167 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
4168 sp_dcc_build_presets_list (tbl);
4169 }
4172 static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject* tbl) {
4174 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4176 gint preset_index = ege_select_one_action_get_active( act );
4177 // This is necessary because EgeSelectOneAction spams us with GObject "changed" signal calls
4178 // even when the preset is not changed. It would be good to replace it with something more
4179 // modern. Index 0 means "No preset", so we don't do anything.
4180 if (preset_index == 0) return;
4182 gint save_presets_index = GPOINTER_TO_INT(g_object_get_data(tbl, "save_presets_index"));
4184 if (preset_index == save_presets_index) {
4185 // this is the Save command
4186 sp_dcc_save_profile(NULL, tbl);
4187 return;
4188 }
4190 if (g_object_get_data(tbl, "presets_blocked"))
4191 return;
4193 // preset_index is one-based so we subtract 1
4194 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
4195 Glib::ustring preset_path = presets.at(preset_index - 1);
4197 if (!preset_path.empty()) {
4198 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
4200 std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(preset_path);
4202 // Shouldn't this be std::map?
4203 for (std::vector<Inkscape::Preferences::Entry>::iterator i = preset.begin(); i != preset.end(); ++i) {
4204 Glib::ustring entry_name = i->getEntryName();
4205 if (entry_name == "id" || entry_name == "name") continue;
4206 void *widget = g_object_get_data(tbl, entry_name.data());
4207 if (widget) {
4208 if (GTK_IS_ADJUSTMENT(widget)) {
4209 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
4210 gtk_adjustment_set_value(adj, i->getDouble());
4211 //std::cout << "set adj " << attr_name << " to " << v << "\n";
4212 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
4213 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
4214 gtk_toggle_action_set_active(toggle, i->getBool());
4215 //std::cout << "set toggle " << attr_name << " to " << v << "\n";
4216 } else {
4217 g_warning("Unknown widget type for preset: %s\n", entry_name.data());
4218 }
4219 } else {
4220 g_warning("Bad key found in a preset record: %s\n", entry_name.data());
4221 }
4222 }
4223 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
4224 }
4225 }
4228 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4229 {
4230 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4231 {
4232 g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(TRUE));
4234 EgeAdjustmentAction* calligraphy_angle = 0;
4236 {
4237 /* Width */
4238 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
4239 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
4240 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
4241 _("Pen Width"), _("Width:"),
4242 _("The width of the calligraphic pen (relative to the visible canvas area)"),
4243 "/tools/calligraphic/width", 15,
4244 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
4245 1, 100, 1.0, 0.0,
4246 labels, values, G_N_ELEMENTS(labels),
4247 sp_ddc_width_value_changed, 0.01, 0, 100 );
4248 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4249 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4250 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4251 }
4253 {
4254 /* Thinning */
4255 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
4256 gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100};
4257 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
4258 _("Stroke Thinning"), _("Thinning:"),
4259 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
4260 "/tools/calligraphic/thinning", 10,
4261 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4262 -100, 100, 1, 0.1,
4263 labels, values, G_N_ELEMENTS(labels),
4264 sp_ddc_velthin_value_changed, 0.01, 0, 100);
4265 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4266 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4267 }
4269 {
4270 /* Angle */
4271 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
4272 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
4273 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
4274 _("Pen Angle"), _("Angle:"),
4275 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
4276 "/tools/calligraphic/angle", 30,
4277 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
4278 -90.0, 90.0, 1.0, 10.0,
4279 labels, values, G_N_ELEMENTS(labels),
4280 sp_ddc_angle_value_changed, 1, 0 );
4281 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4282 g_object_set_data( holder, "angle_action", eact );
4283 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4284 calligraphy_angle = eact;
4285 }
4287 {
4288 /* Fixation */
4289 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
4290 gdouble values[] = {0, 20, 40, 60, 90, 100};
4291 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
4292 _("Fixation"), _("Fixation:"),
4293 _("Angle behavior (0 = nib always perpendicular to stroke direction, 100 = fixed angle)"),
4294 "/tools/calligraphic/flatness", 90,
4295 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4296 0.0, 100, 1.0, 10.0,
4297 labels, values, G_N_ELEMENTS(labels),
4298 sp_ddc_flatness_value_changed, 0.01, 0, 100 );
4299 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4300 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4301 }
4303 {
4304 /* Cap Rounding */
4305 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
4306 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
4307 // TRANSLATORS: "cap" means "end" (both start and finish) here
4308 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
4309 _("Cap rounding"), _("Caps:"),
4310 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
4311 "/tools/calligraphic/cap_rounding", 0.0,
4312 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4313 0.0, 5.0, 0.01, 0.1,
4314 labels, values, G_N_ELEMENTS(labels),
4315 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
4316 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4317 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4318 }
4320 {
4321 /* Tremor */
4322 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
4323 gdouble values[] = {0, 10, 20, 40, 60, 100};
4324 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
4325 _("Stroke Tremor"), _("Tremor:"),
4326 _("Increase to make strokes rugged and trembling"),
4327 "/tools/calligraphic/tremor", 0.0,
4328 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4329 0.0, 100, 1, 0.0,
4330 labels, values, G_N_ELEMENTS(labels),
4331 sp_ddc_tremor_value_changed, 0.01, 0, 100 );
4333 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4334 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4335 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4336 }
4338 {
4339 /* Wiggle */
4340 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
4341 gdouble values[] = {0, 20, 40, 60, 100};
4342 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
4343 _("Pen Wiggle"), _("Wiggle:"),
4344 _("Increase to make the pen waver and wiggle"),
4345 "/tools/calligraphic/wiggle", 0.0,
4346 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4347 0.0, 100, 1, 0.0,
4348 labels, values, G_N_ELEMENTS(labels),
4349 sp_ddc_wiggle_value_changed, 0.01, 0, 100 );
4350 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4351 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4352 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4353 }
4355 {
4356 /* Mass */
4357 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
4358 gdouble values[] = {0.0, 2, 10, 20, 50, 100};
4359 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
4360 _("Pen Mass"), _("Mass:"),
4361 _("Increase to make the pen drag behind, as if slowed by inertia"),
4362 "/tools/calligraphic/mass", 2.0,
4363 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4364 0.0, 100, 1, 0.0,
4365 labels, values, G_N_ELEMENTS(labels),
4366 sp_ddc_mass_value_changed, 0.01, 0, 100 );
4367 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4368 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4369 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4370 }
4373 /* Trace Background button */
4374 {
4375 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
4376 _("Trace Background"),
4377 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
4378 "trace_background",
4379 Inkscape::ICON_SIZE_DECORATION );
4380 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4381 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), holder);
4382 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/tracebackground", false) );
4383 g_object_set_data( holder, "tracebackground", act );
4384 }
4386 /* Use Pressure button */
4387 {
4388 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
4389 _("Pressure"),
4390 _("Use the pressure of the input device to alter the width of the pen"),
4391 "use_pressure",
4392 Inkscape::ICON_SIZE_DECORATION );
4393 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4394 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), holder);
4395 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/usepressure", true) );
4396 g_object_set_data( holder, "usepressure", act );
4397 }
4399 /* Use Tilt button */
4400 {
4401 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
4402 _("Tilt"),
4403 _("Use the tilt of the input device to alter the angle of the pen's nib"),
4404 "use_tilt",
4405 Inkscape::ICON_SIZE_DECORATION );
4406 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4407 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), holder );
4408 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs->getBool("/tools/calligraphic/usetilt", true) );
4409 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/usetilt", true) );
4410 g_object_set_data( holder, "usetilt", act );
4411 }
4413 /*calligraphic profile */
4414 {
4415 GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
4416 EgeSelectOneAction* act1 = ege_select_one_action_new ("SetProfileAction", "" , (_("Choose a preset")), NULL, GTK_TREE_MODEL(model));
4417 ege_select_one_action_set_appearance (act1, "compact");
4418 g_object_set_data (holder, "profile_selector", act1 );
4420 g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(FALSE));
4422 sp_dcc_build_presets_list (holder);
4424 g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder);
4425 gtk_action_group_add_action(mainActions, GTK_ACTION(act1));
4426 }
4427 }
4428 }
4431 //########################
4432 //## Circle / Arc ##
4433 //########################
4435 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
4436 {
4437 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
4438 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
4440 if (v1 == 0 && v2 == 0) {
4441 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
4442 gtk_action_set_sensitive( ocb, FALSE );
4443 gtk_action_set_sensitive( make_whole, FALSE );
4444 }
4445 } else {
4446 gtk_action_set_sensitive( ocb, TRUE );
4447 gtk_action_set_sensitive( make_whole, TRUE );
4448 }
4449 }
4451 static void
4452 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
4453 {
4454 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4456 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
4457 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4458 prefs->setDouble(Glib::ustring("/tools/shapes/arc") + value_name, (adj->value * M_PI)/ 180);
4459 }
4461 // quit if run by the attr_changed listener
4462 if (g_object_get_data( tbl, "freeze" )) {
4463 return;
4464 }
4466 // in turn, prevent listener from responding
4467 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4469 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
4471 bool modmade = false;
4472 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
4473 items != NULL;
4474 items = items->next)
4475 {
4476 SPItem *item = SP_ITEM(items->data);
4478 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
4480 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
4481 SPArc *arc = SP_ARC(item);
4483 if (!strcmp(value_name, "start"))
4484 ge->start = (adj->value * M_PI)/ 180;
4485 else
4486 ge->end = (adj->value * M_PI)/ 180;
4488 sp_genericellipse_normalize(ge);
4489 ((SPObject *)arc)->updateRepr();
4490 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
4492 modmade = true;
4493 }
4494 }
4496 g_free(namespaced_name);
4498 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
4500 sp_arctb_sensitivize( tbl, adj->value, other->value );
4502 if (modmade) {
4503 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
4504 _("Arc: Change start/end"));
4505 }
4507 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4508 }
4511 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
4512 {
4513 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
4514 }
4516 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
4517 {
4518 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
4519 }
4522 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
4523 {
4524 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4525 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
4526 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4527 prefs->setBool("/tools/shapes/arc/open", ege_select_one_action_get_active(act) != 0);
4528 }
4530 // quit if run by the attr_changed listener
4531 if (g_object_get_data( tbl, "freeze" )) {
4532 return;
4533 }
4535 // in turn, prevent listener from responding
4536 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4538 bool modmade = false;
4540 if ( ege_select_one_action_get_active(act) != 0 ) {
4541 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
4542 items != NULL;
4543 items = items->next)
4544 {
4545 if (SP_IS_ARC((SPItem *) items->data)) {
4546 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
4547 repr->setAttribute("sodipodi:open", "true");
4548 SP_OBJECT((SPItem *) items->data)->updateRepr();
4549 modmade = true;
4550 }
4551 }
4552 } else {
4553 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
4554 items != NULL;
4555 items = items->next)
4556 {
4557 if (SP_IS_ARC((SPItem *) items->data)) {
4558 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
4559 repr->setAttribute("sodipodi:open", NULL);
4560 SP_OBJECT((SPItem *) items->data)->updateRepr();
4561 modmade = true;
4562 }
4563 }
4564 }
4566 if (modmade) {
4567 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
4568 _("Arc: Change open/closed"));
4569 }
4571 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4572 }
4574 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
4575 {
4576 GtkAdjustment *adj;
4577 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
4578 gtk_adjustment_set_value(adj, 0.0);
4579 gtk_adjustment_value_changed(adj);
4581 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
4582 gtk_adjustment_set_value(adj, 0.0);
4583 gtk_adjustment_value_changed(adj);
4585 spinbutton_defocus( GTK_OBJECT(obj) );
4586 }
4588 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
4589 gchar const */*old_value*/, gchar const */*new_value*/,
4590 bool /*is_interactive*/, gpointer data)
4591 {
4592 GObject *tbl = G_OBJECT(data);
4594 // quit if run by the _changed callbacks
4595 if (g_object_get_data( tbl, "freeze" )) {
4596 return;
4597 }
4599 // in turn, prevent callbacks from responding
4600 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4602 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
4603 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
4605 GtkAdjustment *adj1,*adj2;
4606 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
4607 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
4608 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
4609 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
4611 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
4613 char const *openstr = NULL;
4614 openstr = repr->attribute("sodipodi:open");
4615 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
4617 if (openstr) {
4618 ege_select_one_action_set_active( ocb, 1 );
4619 } else {
4620 ege_select_one_action_set_active( ocb, 0 );
4621 }
4623 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4624 }
4626 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
4627 NULL, /* child_added */
4628 NULL, /* child_removed */
4629 arc_tb_event_attr_changed,
4630 NULL, /* content_changed */
4631 NULL /* order_changed */
4632 };
4635 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
4636 {
4637 int n_selected = 0;
4638 Inkscape::XML::Node *repr = NULL;
4640 purge_repr_listener( tbl, tbl );
4642 for (GSList const *items = selection->itemList();
4643 items != NULL;
4644 items = items->next)
4645 {
4646 if (SP_IS_ARC((SPItem *) items->data)) {
4647 n_selected++;
4648 repr = SP_OBJECT_REPR((SPItem *) items->data);
4649 }
4650 }
4652 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
4654 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
4655 if (n_selected == 0) {
4656 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
4657 } else if (n_selected == 1) {
4658 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
4659 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
4661 if (repr) {
4662 g_object_set_data( tbl, "repr", repr );
4663 Inkscape::GC::anchor(repr);
4664 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
4665 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
4666 }
4667 } else {
4668 // FIXME: implement averaging of all parameters for multiple selected
4669 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
4670 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
4671 sp_arctb_sensitivize( tbl, 1, 0 );
4672 }
4673 }
4676 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4677 {
4678 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4680 EgeAdjustmentAction* eact = 0;
4681 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
4684 {
4685 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
4686 ege_output_action_set_use_markup( act, TRUE );
4687 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4688 g_object_set_data( holder, "mode_action", act );
4689 }
4691 /* Start */
4692 {
4693 eact = create_adjustment_action( "ArcStartAction",
4694 _("Start"), _("Start:"),
4695 _("The angle (in degrees) from the horizontal to the arc's start point"),
4696 "/tools/shapes/arc/start", 0.0,
4697 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
4698 -360.0, 360.0, 1.0, 10.0,
4699 0, 0, 0,
4700 sp_arctb_start_value_changed);
4701 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4702 }
4704 /* End */
4705 {
4706 eact = create_adjustment_action( "ArcEndAction",
4707 _("End"), _("End:"),
4708 _("The angle (in degrees) from the horizontal to the arc's end point"),
4709 "/tools/shapes/arc/end", 0.0,
4710 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
4711 -360.0, 360.0, 1.0, 10.0,
4712 0, 0, 0,
4713 sp_arctb_end_value_changed);
4714 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4715 }
4717 /* Segments / Pie checkbox */
4718 {
4719 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
4721 GtkTreeIter iter;
4722 gtk_list_store_append( model, &iter );
4723 gtk_list_store_set( model, &iter,
4724 0, _("Closed arc"),
4725 1, _("Switch to segment (closed shape with two radii)"),
4726 2, "circle_closed_arc",
4727 -1 );
4729 gtk_list_store_append( model, &iter );
4730 gtk_list_store_set( model, &iter,
4731 0, _("Open Arc"),
4732 1, _("Switch to arc (unclosed shape)"),
4733 2, "circle_open_arc",
4734 -1 );
4736 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
4737 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
4738 g_object_set_data( holder, "open_action", act );
4740 ege_select_one_action_set_appearance( act, "full" );
4741 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
4742 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
4743 ege_select_one_action_set_icon_column( act, 2 );
4744 ege_select_one_action_set_icon_size( act, secondarySize );
4745 ege_select_one_action_set_tooltip_column( act, 1 );
4747 bool isClosed = !prefs->getBool("/tools/shapes/arc/open", false);
4748 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
4749 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
4750 }
4752 /* Make Whole */
4753 {
4754 InkAction* inky = ink_action_new( "ArcResetAction",
4755 _("Make whole"),
4756 _("Make the shape a whole ellipse, not arc or segment"),
4757 "reset_circle",
4758 secondarySize );
4759 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
4760 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4761 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
4762 g_object_set_data( holder, "make_whole", inky );
4763 }
4765 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
4766 // sensitivize make whole and open checkbox
4767 {
4768 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
4769 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
4770 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
4771 }
4774 sigc::connection *connection = new sigc::connection(
4775 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
4776 );
4777 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
4778 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
4779 }
4784 // toggle button callbacks and updaters
4786 //########################
4787 //## Dropper ##
4788 //########################
4790 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
4791 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4792 prefs->setInt( "/tools/dropper/pick", gtk_toggle_action_get_active( act ) );
4793 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
4794 if ( set_action ) {
4795 if ( gtk_toggle_action_get_active( act ) ) {
4796 gtk_action_set_sensitive( set_action, TRUE );
4797 } else {
4798 gtk_action_set_sensitive( set_action, FALSE );
4799 }
4800 }
4802 spinbutton_defocus(GTK_OBJECT(tbl));
4803 }
4805 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
4806 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4807 prefs->setBool( "/tools/dropper/setalpha", gtk_toggle_action_get_active( act ) );
4808 spinbutton_defocus(GTK_OBJECT(tbl));
4809 }
4812 /**
4813 * Dropper auxiliary toolbar construction and setup.
4814 *
4815 * TODO: Would like to add swatch of current color.
4816 * TODO: Add queue of last 5 or so colors selected with new swatches so that
4817 * can drag and drop places. Will provide a nice mixing palette.
4818 */
4819 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
4820 {
4821 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4822 gint pickAlpha = prefs->getInt( "/tools/dropper/pick", 1 );
4824 {
4825 EgeOutputAction* act = ege_output_action_new( "DropperOpacityAction", _("Opacity:"), "", 0 );
4826 ege_output_action_set_use_markup( act, TRUE );
4827 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4828 }
4830 {
4831 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
4832 _("Pick opacity"),
4833 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
4834 NULL,
4835 Inkscape::ICON_SIZE_DECORATION );
4836 g_object_set( act, "short_label", _("Pick"), NULL );
4837 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4838 g_object_set_data( holder, "pick_action", act );
4839 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
4840 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
4841 }
4843 {
4844 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
4845 _("Assign opacity"),
4846 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
4847 NULL,
4848 Inkscape::ICON_SIZE_DECORATION );
4849 g_object_set( act, "short_label", _("Assign"), NULL );
4850 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4851 g_object_set_data( holder, "set_action", act );
4852 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/dropper/setalpha", true) );
4853 // make sure it's disabled if we're not picking alpha
4854 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
4855 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
4856 }
4857 }
4860 //########################
4861 //## LPETool ##
4862 //########################
4864 // the subtools from which the toolbar is built automatically are listed in lpe-tool-context.h
4866 // this is called when the mode is changed via the toolbar (i.e., one of the subtool buttons is pressed)
4867 static void sp_lpetool_mode_changed(EgeSelectOneAction *act, GObject *tbl)
4868 {
4869 using namespace Inkscape::LivePathEffect;
4871 SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop");
4872 SPEventContext *ec = desktop->event_context;
4873 if (!SP_IS_LPETOOL_CONTEXT(ec)) {
4874 return;
4875 }
4877 // only take action if run by the attr_changed listener
4878 if (!g_object_get_data(tbl, "freeze")) {
4879 // in turn, prevent listener from responding
4880 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
4882 gint mode = ege_select_one_action_get_active(act);
4883 EffectType type = lpesubtools[mode];
4885 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
4886 bool success = lpetool_try_construction(lc, type);
4887 if (success) {
4888 // since the construction was already performed, we set the state back to inactive
4889 ege_select_one_action_set_active(act, 0);
4890 mode = 0;
4891 } else {
4892 // switch to the chosen subtool
4893 SP_LPETOOL_CONTEXT(desktop->event_context)->mode = type;
4894 }
4896 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
4897 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4898 prefs->setInt( "/tools/lpetool/mode", mode );
4899 }
4901 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE));
4902 }
4903 }
4905 void sp_lpetool_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject */*tbl*/)
4906 {
4907 SPEventContext *ec = selection->desktop()->event_context;
4908 if (!SP_IS_LPETOOL_CONTEXT(ec))
4909 return;
4911 lpetool_update_measuring_items(SP_LPETOOL_CONTEXT(ec));
4912 }
4914 void
4915 sp_lpetool_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl)
4916 {
4917 using namespace Inkscape::LivePathEffect;
4918 SPEventContext *ec = selection->desktop()->event_context;
4919 if (!SP_IS_LPETOOL_CONTEXT(ec))
4920 return;
4921 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(ec);
4923 lpetool_delete_measuring_items(lc);
4924 lpetool_create_measuring_items(lc, selection);
4926 // activate line segment combo box if a single item with LPELineSegment is selected
4927 GtkAction* w = GTK_ACTION(g_object_get_data(tbl, "lpetool_line_segment_action"));
4928 SPItem *item = selection->singleItem();
4929 if (item && SP_IS_LPE_ITEM(item) && lpetool_item_has_construction(lc, item)) {
4930 SPLPEItem *lpeitem = SP_LPE_ITEM(item);
4931 Effect* lpe = sp_lpe_item_get_current_lpe(lpeitem);
4932 if (lpe && lpe->effectType() == LINE_SEGMENT) {
4933 LPELineSegment *lpels = static_cast<LPELineSegment*>(lpe);
4934 g_object_set_data(tbl, "currentlpe", lpe);
4935 g_object_set_data(tbl, "currentlpeitem", lpeitem);
4936 gtk_action_set_sensitive(w, TRUE);
4937 ege_select_one_action_set_active(EGE_SELECT_ONE_ACTION(w), lpels->end_type.get_value());
4938 } else {
4939 g_object_set_data(tbl, "currentlpe", NULL);
4940 g_object_set_data(tbl, "currentlpeitem", NULL);
4941 gtk_action_set_sensitive(w, FALSE);
4942 }
4943 } else {
4944 g_object_set_data(tbl, "currentlpe", NULL);
4945 g_object_set_data(tbl, "currentlpeitem", NULL);
4946 gtk_action_set_sensitive(w, FALSE);
4947 }
4948 }
4950 static void
4951 lpetool_toggle_show_bbox (GtkToggleAction *act, gpointer data) {
4952 SPDesktop *desktop = static_cast<SPDesktop *>(data);
4953 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4955 bool show = gtk_toggle_action_get_active( act );
4956 prefs->setBool("/tools/lpetool/show_bbox", show);
4958 if (tools_isactive(desktop, TOOLS_LPETOOL)) {
4959 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
4960 lpetool_context_reset_limiting_bbox(lc);
4961 }
4962 }
4964 static void
4965 lpetool_toggle_show_measuring_info (GtkToggleAction *act, GObject *tbl) {
4966 SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop"));
4967 if (!tools_isactive(desktop, TOOLS_LPETOOL))
4968 return;
4970 GtkAction *unitact = static_cast<GtkAction*>(g_object_get_data(tbl, "lpetool_units_action"));
4971 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
4972 if (tools_isactive(desktop, TOOLS_LPETOOL)) {
4973 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4974 bool show = gtk_toggle_action_get_active( act );
4975 prefs->setBool("/tools/lpetool/show_measuring_info", show);
4976 lpetool_show_measuring_info(lc, show);
4977 gtk_action_set_sensitive(GTK_ACTION(unitact), show);
4978 }
4979 }
4981 static void lpetool_unit_changed(GtkAction* /*act*/, GObject* tbl) {
4982 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker"));
4983 SPUnit const *unit = tracker->getActiveUnit();
4984 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4985 prefs->setInt("/tools/lpetool/unitid", unit->unit_id);
4987 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4988 if (SP_IS_LPETOOL_CONTEXT(desktop->event_context)) {
4989 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
4990 lpetool_delete_measuring_items(lc);
4991 lpetool_create_measuring_items(lc);
4992 }
4993 }
4995 static void
4996 lpetool_toggle_set_bbox (GtkToggleAction *act, gpointer data) {
4997 SPDesktop *desktop = static_cast<SPDesktop *>(data);
4998 Inkscape::Selection *selection = desktop->selection;
5000 Geom::OptRect bbox = selection->bounds();
5002 if (bbox) {
5003 Geom::Point A(bbox->min());
5004 Geom::Point B(bbox->max());
5006 A *= desktop->doc2dt();
5007 B *= desktop->doc2dt();
5009 // TODO: should we provide a way to store points in prefs?
5010 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5011 prefs->setDouble("/tools/lpetool/bbox_upperleftx", A[Geom::X]);
5012 prefs->setDouble("/tools/lpetool/bbox_upperlefty", A[Geom::Y]);
5013 prefs->setDouble("/tools/lpetool/bbox_lowerrightx", B[Geom::X]);
5014 prefs->setDouble("/tools/lpetool/bbox_lowerrighty", B[Geom::Y]);
5016 lpetool_context_reset_limiting_bbox(SP_LPETOOL_CONTEXT(desktop->event_context));
5017 }
5019 gtk_toggle_action_set_active(act, false);
5020 }
5022 static void
5023 sp_line_segment_build_list(GObject *tbl)
5024 {
5025 g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(TRUE));
5027 EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "lpetool_line_segment_action"));
5028 GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
5029 gtk_list_store_clear (model);
5031 // TODO: we add the entries of rht combo box manually; later this should be done automatically
5032 {
5033 GtkTreeIter iter;
5034 gtk_list_store_append( model, &iter );
5035 gtk_list_store_set( model, &iter, 0, _("Closed"), 1, 0, -1 );
5036 gtk_list_store_append( model, &iter );
5037 gtk_list_store_set( model, &iter, 0, _("Open start"), 1, 1, -1 );
5038 gtk_list_store_append( model, &iter );
5039 gtk_list_store_set( model, &iter, 0, _("Open end"), 1, 2, -1 );
5040 gtk_list_store_append( model, &iter );
5041 gtk_list_store_set( model, &iter, 0, _("Open both"), 1, 3, -1 );
5042 }
5044 g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(FALSE));
5045 }
5047 static void
5048 sp_lpetool_change_line_segment_type(EgeSelectOneAction* act, GObject* tbl) {
5049 using namespace Inkscape::LivePathEffect;
5051 // quit if run by the attr_changed listener
5052 if (g_object_get_data(tbl, "freeze")) {
5053 return;
5054 }
5056 // in turn, prevent listener from responding
5057 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
5059 LPELineSegment *lpe = static_cast<LPELineSegment *>(g_object_get_data(tbl, "currentlpe"));
5060 SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem"));
5061 if (lpeitem) {
5062 SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem"));
5063 lpe->end_type.param_set_value(static_cast<Inkscape::LivePathEffect::EndType>(ege_select_one_action_get_active(act)));
5064 sp_lpe_item_update_patheffect(lpeitem, true, true);
5065 }
5067 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5068 }
5070 static void
5071 lpetool_open_lpe_dialog (GtkToggleAction *act, gpointer data) {
5072 SPDesktop *desktop = static_cast<SPDesktop *>(data);
5074 if (tools_isactive(desktop, TOOLS_LPETOOL)) {
5075 sp_action_perform(Inkscape::Verb::get(SP_VERB_DIALOG_LIVE_PATH_EFFECT)->get_action(desktop), NULL);
5076 }
5077 gtk_toggle_action_set_active(act, false);
5078 }
5080 static void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5081 {
5082 UnitTracker* tracker = new UnitTracker(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
5083 tracker->setActiveUnit(sp_desktop_namedview(desktop)->doc_units);
5084 g_object_set_data(holder, "tracker", tracker);
5085 SPUnit const *unit = tracker->getActiveUnit();
5087 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5088 prefs->setInt("/tools/lpetool/unitid", unit->unit_id);
5090 /** Automatically create a list of LPEs that get added to the toolbar **/
5091 {
5092 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
5094 GtkTreeIter iter;
5096 // the first toggle button represents the state that no subtool is active (remove this when
5097 // this can be modeled by EgeSelectOneAction or some other action)
5098 gtk_list_store_append( model, &iter );
5099 gtk_list_store_set( model, &iter,
5100 0, _("All inactive"),
5101 1, _("No geometric tool is active"),
5102 2, _("all_inactive"),
5103 -1 );
5105 Inkscape::LivePathEffect::EffectType type;
5106 for (int i = 1; i < num_subtools; ++i) { // we start with i = 1 because INVALID_LPE was already added
5107 type = lpesubtools[i];
5108 gtk_list_store_append( model, &iter );
5109 gtk_list_store_set( model, &iter,
5110 0, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
5111 1, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
5112 2, Inkscape::LivePathEffect::LPETypeConverter.get_key(type).c_str(),
5113 -1 );
5114 }
5116 EgeSelectOneAction* act = ege_select_one_action_new( "LPEToolModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
5117 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
5118 g_object_set_data( holder, "lpetool_mode_action", act );
5120 ege_select_one_action_set_appearance( act, "full" );
5121 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
5122 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
5123 ege_select_one_action_set_icon_column( act, 2 );
5124 ege_select_one_action_set_tooltip_column( act, 1 );
5126 gint lpeToolMode = prefs->getInt("/tools/lpetool/mode", 0);
5127 ege_select_one_action_set_active( act, lpeToolMode );
5128 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_mode_changed), holder );
5129 }
5131 /* Show limiting bounding box */
5132 {
5133 InkToggleAction* act = ink_toggle_action_new( "LPEShowBBoxAction",
5134 _("Show limiting bounding box"),
5135 _("Show bounding box (used to cut infinite lines)"),
5136 "lpetool_show_bbox",
5137 Inkscape::ICON_SIZE_DECORATION );
5138 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5139 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_bbox), desktop );
5140 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_bbox", true ) );
5141 }
5143 /* Set limiting bounding box to bbox of current selection */
5144 {
5145 InkToggleAction* act = ink_toggle_action_new( "LPEBBoxFromSelectionAction",
5146 _("Get limiting bounding box from selection"),
5147 _("Set limiting bounding box (used to cut infinite lines) to the bounding box of current selection"),
5148 "lpetool_set_bbox",
5149 Inkscape::ICON_SIZE_DECORATION );
5150 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5151 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_set_bbox), desktop );
5152 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE );
5153 }
5156 /* Combo box to choose line segment type */
5157 {
5158 GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
5159 EgeSelectOneAction* act = ege_select_one_action_new ("LPELineSegmentAction", "" , (_("Choose a line segment type")), NULL, GTK_TREE_MODEL(model));
5160 ege_select_one_action_set_appearance (act, "compact");
5161 g_object_set_data (holder, "lpetool_line_segment_action", act );
5163 g_object_set_data(holder, "line_segment_list_blocked", GINT_TO_POINTER(FALSE));
5165 sp_line_segment_build_list (holder);
5167 g_signal_connect(G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_change_line_segment_type), holder);
5168 gtk_action_set_sensitive( GTK_ACTION(act), FALSE );
5169 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
5170 }
5172 /* Display measuring info for selected items */
5173 {
5174 InkToggleAction* act = ink_toggle_action_new( "LPEMeasuringAction",
5175 _("Display measuring info"),
5176 _("Display measuring info for selected items"),
5177 "lpetool_measuring_info",
5178 Inkscape::ICON_SIZE_DECORATION );
5179 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5180 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_measuring_info), holder );
5181 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_measuring_info", true ) );
5182 }
5184 // add the units menu
5185 {
5186 GtkAction* act = tracker->createAction( "LPEToolUnitsAction", _("Units"), ("") );
5187 gtk_action_group_add_action( mainActions, act );
5188 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(lpetool_unit_changed), (GObject*)holder );
5189 g_object_set_data(holder, "lpetool_units_action", act);
5190 gtk_action_set_sensitive(act, prefs->getBool("/tools/lpetool/show_measuring_info", true));
5191 }
5193 /* Open LPE dialog (to adapt parameters numerically) */
5194 {
5195 InkToggleAction* act = ink_toggle_action_new( "LPEOpenLPEDialogAction",
5196 _("Open LPE dialog"),
5197 _("Open LPE dialog (to adapt parameters numerically)"),
5198 "lpetool_open_lpe_dialog",
5199 Inkscape::ICON_SIZE_DECORATION );
5200 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5201 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_open_lpe_dialog), desktop );
5202 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE );
5203 }
5205 //watch selection
5206 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
5208 sigc::connection *c_selection_modified =
5209 new sigc::connection (sp_desktop_selection (desktop)->connectModified
5210 (sigc::bind (sigc::ptr_fun (sp_lpetool_toolbox_sel_modified), (GObject*)holder)));
5211 pool->add_connection ("selection-modified", c_selection_modified);
5213 sigc::connection *c_selection_changed =
5214 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
5215 (sigc::bind (sigc::ptr_fun(sp_lpetool_toolbox_sel_changed), (GObject*)holder)));
5216 pool->add_connection ("selection-changed", c_selection_changed);
5217 }
5219 //########################
5220 //## Eraser ##
5221 //########################
5223 static void sp_erc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
5224 {
5225 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5226 prefs->setDouble( "/tools/eraser/width", adj->value * 0.01 );
5227 update_presets_list(tbl);
5228 }
5230 static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
5231 {
5232 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
5233 bool eraserMode = ege_select_one_action_get_active( act ) != 0;
5234 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
5235 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5236 prefs->setBool( "/tools/eraser/mode", eraserMode );
5237 }
5239 // only take action if run by the attr_changed listener
5240 if (!g_object_get_data( tbl, "freeze" )) {
5241 // in turn, prevent listener from responding
5242 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
5244 if ( eraserMode != 0 ) {
5245 } else {
5246 }
5247 // TODO finish implementation
5249 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5250 }
5251 }
5253 static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5254 {
5255 {
5256 /* Width */
5257 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
5258 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
5259 EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction",
5260 _("Pen Width"), _("Width:"),
5261 _("The width of the eraser pen (relative to the visible canvas area)"),
5262 "/tools/eraser/width", 15,
5263 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser",
5264 1, 100, 1.0, 0.0,
5265 labels, values, G_N_ELEMENTS(labels),
5266 sp_erc_width_value_changed, 0.01, 0, 100 );
5267 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
5268 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5269 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
5270 }
5272 {
5273 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
5275 GtkTreeIter iter;
5276 gtk_list_store_append( model, &iter );
5277 gtk_list_store_set( model, &iter,
5278 0, _("Delete"),
5279 1, _("Delete objects touched by the eraser"),
5280 2, "delete_object",
5281 -1 );
5283 gtk_list_store_append( model, &iter );
5284 gtk_list_store_set( model, &iter,
5285 0, _("Cut"),
5286 1, _("Cut out from objects"),
5287 2, "difference",
5288 -1 );
5290 EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
5291 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
5292 g_object_set_data( holder, "eraser_mode_action", act );
5294 ege_select_one_action_set_appearance( act, "full" );
5295 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
5296 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
5297 ege_select_one_action_set_icon_column( act, 2 );
5298 ege_select_one_action_set_tooltip_column( act, 1 );
5300 /// @todo Convert to boolean?
5301 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5302 gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
5303 ege_select_one_action_set_active( act, eraserMode );
5304 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder );
5305 }
5307 }
5309 //########################
5310 //## Text Toolbox ##
5311 //########################
5312 /*
5313 static void
5314 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
5315 {
5316 //Call back for letter sizing spinbutton
5317 }
5319 static void
5320 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
5321 {
5322 //Call back for line height spinbutton
5323 }
5325 static void
5326 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
5327 {
5328 //Call back for horizontal kerning spinbutton
5329 }
5331 static void
5332 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
5333 {
5334 //Call back for vertical kerning spinbutton
5335 }
5337 static void
5338 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
5339 {
5340 //Call back for letter rotation spinbutton
5341 }*/
5343 namespace {
5345 bool popdown_visible = false;
5346 bool popdown_hasfocus = false;
5348 void
5349 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
5350 {
5351 SPStyle *query =
5352 sp_style_new (SP_ACTIVE_DOCUMENT);
5354 // int result_fontspec = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
5356 int result_family =
5357 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
5359 int result_style =
5360 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
5362 int result_numbers =
5363 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5365 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
5367 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5368 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) {
5369 // there are no texts in selection, read from prefs
5371 sp_style_read_from_prefs(query, "/tools/text");
5373 if (g_object_get_data(tbl, "text_style_from_prefs")) {
5374 // do not reset the toolbar style from prefs if we already did it last time
5375 sp_style_unref(query);
5376 return;
5377 }
5378 g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(TRUE));
5379 } else {
5380 g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(FALSE));
5381 }
5383 if (query->text)
5384 {
5385 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
5386 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
5387 gtk_entry_set_text (GTK_ENTRY (entry), "");
5389 } else if (query->text->font_specification.value || query->text->font_family.value) {
5391 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
5393 // Get the font that corresponds
5394 Glib::ustring familyName;
5396 font_instance * font = font_factory::Default()->FaceFromStyle(query);
5397 if (font) {
5398 familyName = font_factory::Default()->GetUIFamilyString(font->descr);
5399 font->Unref();
5400 font = NULL;
5401 }
5403 gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
5405 Gtk::TreePath path;
5406 try {
5407 path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
5408 } catch (...) {
5409 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
5410 sp_style_unref(query);
5411 return;
5412 }
5414 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
5415 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
5417 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
5419 gtk_tree_selection_select_path (tselection, path.gobj());
5420 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
5422 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
5423 }
5425 //Size
5426 {
5427 GtkWidget *cbox = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "combo-box-size"));
5428 gchar *const str = g_strdup_printf("%.5g", query->font_size.computed);
5429 g_object_set_data(tbl, "size-block", gpointer(1));
5430 gtk_entry_set_text(GTK_ENTRY(GTK_BIN(cbox)->child), str);
5431 g_object_set_data(tbl, "size-block", gpointer(0));
5432 g_free(str);
5433 }
5435 //Anchor
5436 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
5437 {
5438 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
5439 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
5440 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5441 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5442 }
5443 else
5444 {
5445 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
5446 {
5447 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
5448 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
5449 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5450 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5451 }
5452 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
5453 {
5454 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
5455 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
5456 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5457 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5458 }
5459 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
5460 {
5461 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
5462 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
5463 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5464 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5465 }
5466 }
5468 //Style
5469 {
5470 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
5472 gboolean active = gtk_toggle_button_get_active (button);
5473 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
5475 if (active != check)
5476 {
5477 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
5478 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
5479 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5480 }
5481 }
5483 {
5484 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
5486 gboolean active = gtk_toggle_button_get_active (button);
5487 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
5489 if (active != check)
5490 {
5491 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
5492 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
5493 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5494 }
5495 }
5497 //Orientation
5498 //locking both buttons, changing one affect all group (both)
5499 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
5500 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
5502 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
5503 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
5505 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
5506 {
5507 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5508 }
5509 else
5510 {
5511 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
5512 }
5513 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5514 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
5515 }
5517 sp_style_unref(query);
5518 }
5520 void
5521 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
5522 {
5523 sp_text_toolbox_selection_changed (selection, tbl);
5524 }
5526 void
5527 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
5528 {
5529 sp_text_toolbox_selection_changed (NULL, tbl);
5530 }
5532 void
5533 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
5534 GObject *tbl)
5535 {
5536 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5537 GtkTreeModel *model = 0;
5538 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
5539 GtkTreeIter iter;
5540 char *family = 0;
5542 gdk_pointer_ungrab (GDK_CURRENT_TIME);
5543 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
5545 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
5546 return;
5547 }
5549 gtk_tree_model_get (model, &iter, 0, &family, -1);
5551 if (g_object_get_data (G_OBJECT (selection), "block"))
5552 {
5553 gtk_entry_set_text (GTK_ENTRY (entry), family);
5554 return;
5555 }
5557 gtk_entry_set_text (GTK_ENTRY (entry), family);
5559 SPStyle *query =
5560 sp_style_new (SP_ACTIVE_DOCUMENT);
5562 int result_fontspec =
5563 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
5565 //font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
5567 SPCSSAttr *css = sp_repr_css_attr_new ();
5570 // First try to get the font spec from the stored value
5571 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
5573 if (fontSpec.empty()) {
5574 // Construct a new font specification if it does not yet exist
5575 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
5576 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
5577 fontFromStyle->Unref();
5578 }
5580 if (!fontSpec.empty()) {
5581 Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
5582 if (!newFontSpec.empty() && fontSpec != newFontSpec) {
5583 font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
5584 if (font) {
5585 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
5587 // Set all the these just in case they were altered when finding the best
5588 // match for the new family and old style...
5590 gchar c[256];
5592 font->Family(c, 256);
5593 sp_repr_css_set_property (css, "font-family", c);
5595 font->Attribute( "weight", c, 256);
5596 sp_repr_css_set_property (css, "font-weight", c);
5598 font->Attribute("style", c, 256);
5599 sp_repr_css_set_property (css, "font-style", c);
5601 font->Attribute("stretch", c, 256);
5602 sp_repr_css_set_property (css, "font-stretch", c);
5604 font->Attribute("variant", c, 256);
5605 sp_repr_css_set_property (css, "font-variant", c);
5607 font->Unref();
5608 }
5609 }
5610 }
5612 // If querying returned nothing, set the default style of the tool (for new texts)
5613 if (result_fontspec == QUERY_STYLE_NOTHING)
5614 {
5615 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5616 prefs->setStyle("/tools/text/style", css);
5617 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
5618 }
5619 else
5620 {
5621 sp_desktop_set_style (desktop, css, true, true);
5622 }
5624 sp_style_unref(query);
5626 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5627 _("Text: Change font family"));
5628 sp_repr_css_attr_unref (css);
5629 g_free(family);
5630 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
5632 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5633 }
5635 /* This is where execution comes when the contents of the font family box have been completed
5636 by the press of the return key */
5637 void
5638 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
5639 GObject *tbl)
5640 {
5641 const char *family = gtk_entry_get_text (entry); // Fetch the requested font family
5643 // Try to match that to a known font. If not, then leave current font alone and remain focused on text box
5644 try {
5645 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
5646 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
5647 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
5648 gtk_tree_selection_select_path (selection, path.gobj());
5649 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
5650 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
5651 } catch (...) {
5652 if (family && strlen (family))
5653 {
5654 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
5655 }
5656 }
5657 }
5659 void
5660 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
5661 gpointer data)
5662 {
5663 if (g_object_get_data (G_OBJECT (button), "block")) return;
5664 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
5665 int prop = GPOINTER_TO_INT(data);
5667 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5668 SPCSSAttr *css = sp_repr_css_attr_new ();
5670 switch (prop)
5671 {
5672 case 0:
5673 {
5674 sp_repr_css_set_property (css, "text-anchor", "start");
5675 sp_repr_css_set_property (css, "text-align", "start");
5676 break;
5677 }
5678 case 1:
5679 {
5680 sp_repr_css_set_property (css, "text-anchor", "middle");
5681 sp_repr_css_set_property (css, "text-align", "center");
5682 break;
5683 }
5685 case 2:
5686 {
5687 sp_repr_css_set_property (css, "text-anchor", "end");
5688 sp_repr_css_set_property (css, "text-align", "end");
5689 break;
5690 }
5692 case 3:
5693 {
5694 sp_repr_css_set_property (css, "text-anchor", "start");
5695 sp_repr_css_set_property (css, "text-align", "justify");
5696 break;
5697 }
5698 }
5700 SPStyle *query =
5701 sp_style_new (SP_ACTIVE_DOCUMENT);
5702 int result_numbers =
5703 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5705 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5706 if (result_numbers == QUERY_STYLE_NOTHING)
5707 {
5708 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5709 prefs->setStyle("/tools/text/style", css);
5710 }
5712 sp_style_unref(query);
5714 sp_desktop_set_style (desktop, css, true, true);
5715 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5716 _("Text: Change alignment"));
5717 sp_repr_css_attr_unref (css);
5719 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5720 }
5722 void
5723 sp_text_toolbox_style_toggled (GtkToggleButton *button,
5724 gpointer data)
5725 {
5726 if (g_object_get_data (G_OBJECT (button), "block")) return;
5728 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5729 SPCSSAttr *css = sp_repr_css_attr_new ();
5730 int prop = GPOINTER_TO_INT(data);
5731 bool active = gtk_toggle_button_get_active (button);
5733 SPStyle *query =
5734 sp_style_new (SP_ACTIVE_DOCUMENT);
5736 int result_fontspec =
5737 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
5739 //int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
5740 //int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
5741 //int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5743 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
5744 Glib::ustring newFontSpec = "";
5746 if (fontSpec.empty()) {
5747 // Construct a new font specification if it does not yet exist
5748 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
5749 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
5750 fontFromStyle->Unref();
5751 }
5753 switch (prop)
5754 {
5755 case 0:
5756 {
5757 if (!fontSpec.empty()) {
5758 newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
5759 }
5760 if (fontSpec != newFontSpec) {
5761 // Don't even set the bold if the font didn't exist on the system
5762 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
5763 }
5764 break;
5765 }
5767 case 1:
5768 {
5769 if (!fontSpec.empty()) {
5770 newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
5771 }
5772 if (fontSpec != newFontSpec) {
5773 // Don't even set the italic if the font didn't exist on the system
5774 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
5775 }
5776 break;
5777 }
5778 }
5780 if (!newFontSpec.empty()) {
5781 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
5782 }
5784 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5785 if (result_fontspec == QUERY_STYLE_NOTHING)
5786 {
5787 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5788 prefs->setStyle("/tools/text/style", css);
5789 }
5791 sp_style_unref(query);
5793 sp_desktop_set_style (desktop, css, true, true);
5794 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5795 _("Text: Change font style"));
5796 sp_repr_css_attr_unref (css);
5798 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5799 }
5801 void
5802 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
5803 gpointer data)
5804 {
5805 if (g_object_get_data (G_OBJECT (button), "block")) {
5806 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
5807 return;
5808 }
5810 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5811 SPCSSAttr *css = sp_repr_css_attr_new ();
5812 int prop = GPOINTER_TO_INT(data);
5814 switch (prop)
5815 {
5816 case 0:
5817 {
5818 sp_repr_css_set_property (css, "writing-mode", "lr");
5819 break;
5820 }
5822 case 1:
5823 {
5824 sp_repr_css_set_property (css, "writing-mode", "tb");
5825 break;
5826 }
5827 }
5829 SPStyle *query =
5830 sp_style_new (SP_ACTIVE_DOCUMENT);
5831 int result_numbers =
5832 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5834 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5835 if (result_numbers == QUERY_STYLE_NOTHING)
5836 {
5837 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5838 prefs->setStyle("/tools/text/style", css);
5839 }
5841 sp_desktop_set_style (desktop, css, true, true);
5842 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
5843 _("Text: Change orientation"));
5844 sp_repr_css_attr_unref (css);
5846 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5847 }
5849 gboolean
5850 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
5851 {
5852 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5853 if (!desktop) return FALSE;
5855 switch (get_group0_keyval (event)) {
5856 case GDK_Escape: // defocus
5857 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5858 sp_text_toolbox_selection_changed (NULL, tbl); // update
5859 return TRUE; // I consumed the event
5860 break;
5861 }
5862 return FALSE;
5863 }
5865 gboolean
5866 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
5867 {
5868 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5869 if (!desktop) return FALSE;
5871 switch (get_group0_keyval (event)) {
5872 case GDK_KP_Enter:
5873 case GDK_Return:
5874 case GDK_Escape: // defocus
5875 gtk_widget_hide (w);
5876 popdown_visible = false;
5877 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5878 return TRUE; // I consumed the event
5879 break;
5880 case GDK_w:
5881 case GDK_W:
5882 if (event->state & GDK_CONTROL_MASK) {
5883 gtk_widget_hide (w);
5884 popdown_visible = false;
5885 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5886 return TRUE; // I consumed the event
5887 }
5888 break;
5889 }
5890 return FALSE;
5891 }
5894 void
5895 sp_text_toolbox_size_changed (GtkComboBox *cbox,
5896 GObject *tbl)
5897 {
5898 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5900 if (g_object_get_data (tbl, "size-block")) return;
5902 // If this is not from selecting a size in the list (in which case get_active will give the
5903 // index of the selected item, otherwise -1) and not from user pressing Enter/Return, do not
5904 // process this event. This fixes GTK's stupid insistence on sending an activate change every
5905 // time any character gets typed or deleted, which made this control nearly unusable in 0.45.
5906 if (gtk_combo_box_get_active (cbox) < 0 && !g_object_get_data (tbl, "enter-pressed"))
5907 return;
5909 gdouble value = -1;
5910 {
5911 gchar *endptr;
5912 gchar *const text = gtk_combo_box_get_active_text(cbox);
5913 if (text) {
5914 value = g_strtod(text, &endptr);
5915 if (endptr == text) { // Conversion failed, non-numeric input.
5916 value = -1;
5917 }
5918 g_free(text);
5919 }
5920 }
5921 if (value <= 0) {
5922 return; // could not parse value
5923 }
5925 SPCSSAttr *css = sp_repr_css_attr_new ();
5926 Inkscape::CSSOStringStream osfs;
5927 osfs << value;
5928 sp_repr_css_set_property (css, "font-size", osfs.str().c_str());
5930 SPStyle *query =
5931 sp_style_new (SP_ACTIVE_DOCUMENT);
5932 int result_numbers =
5933 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
5935 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
5936 if (result_numbers == QUERY_STYLE_NOTHING)
5937 {
5938 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5939 prefs->setStyle("/tools/text/style", css);
5940 }
5942 sp_style_unref(query);
5944 sp_desktop_set_style (desktop, css, true, true);
5945 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
5946 _("Text: Change font size"));
5947 sp_repr_css_attr_unref (css);
5949 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5950 }
5952 gboolean
5953 sp_text_toolbox_size_focusout (GtkWidget */*w*/, GdkEventFocus */*event*/, GObject *tbl)
5954 {
5955 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5956 if (!desktop) return FALSE;
5958 if (!g_object_get_data (tbl, "esc-pressed")) {
5959 g_object_set_data (tbl, "enter-pressed", gpointer(1));
5960 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
5961 sp_text_toolbox_size_changed (cbox, tbl);
5962 g_object_set_data (tbl, "enter-pressed", gpointer(0));
5963 }
5964 return FALSE; // I consumed the event
5965 }
5968 gboolean
5969 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
5970 {
5971 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
5972 if (!desktop) return FALSE;
5974 switch (get_group0_keyval (event)) {
5975 case GDK_Escape: // defocus
5976 g_object_set_data (tbl, "esc-pressed", gpointer(1));
5977 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5978 g_object_set_data (tbl, "esc-pressed", gpointer(0));
5979 return TRUE; // I consumed the event
5980 break;
5981 case GDK_Return: // defocus
5982 case GDK_KP_Enter:
5983 g_object_set_data (tbl, "enter-pressed", gpointer(1));
5984 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
5985 sp_text_toolbox_size_changed (cbox, tbl);
5986 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
5987 g_object_set_data (tbl, "enter-pressed", gpointer(0));
5988 return TRUE; // I consumed the event
5989 break;
5990 }
5991 return FALSE;
5992 }
5994 void
5995 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
5996 GObject *tbl)
5997 {
5998 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
5999 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
6000 int x, y;
6002 if (!popdown_visible)
6003 {
6004 gdk_window_get_origin (widget->window, &x, &y);
6005 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
6006 gtk_widget_show_all (popdown);
6007 //sp_transientize (popdown);
6009 gdk_pointer_grab (widget->window, TRUE,
6010 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
6011 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
6012 GDK_POINTER_MOTION_MASK),
6013 NULL, NULL, GDK_CURRENT_TIME);
6015 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
6017 popdown_visible = true;
6018 }
6019 else
6020 {
6021 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6022 gdk_pointer_ungrab (GDK_CURRENT_TIME);
6023 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
6024 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6025 gtk_widget_hide (popdown);
6026 popdown_visible = false;
6027 }
6028 }
6030 gboolean
6031 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
6032 GdkEventFocus */*event*/,
6033 GObject */*tbl*/)
6034 {
6035 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
6036 return FALSE;
6037 }
6039 gboolean
6040 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
6041 GdkEventFocus */*event*/,
6042 GObject */*tbl*/)
6043 {
6044 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6046 if (popdown_hasfocus) {
6047 gtk_widget_hide (popdown);
6048 popdown_hasfocus = false;
6049 popdown_visible = false;
6050 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6051 return TRUE;
6052 }
6053 return FALSE;
6054 }
6056 gboolean
6057 sp_text_toolbox_popdown_focus_in (GtkWidget */*popdown*/,
6058 GdkEventFocus */*event*/,
6059 GObject */*tbl*/)
6060 {
6061 popdown_hasfocus = true;
6062 return TRUE;
6063 }
6066 void
6067 cell_data_func (GtkTreeViewColumn */*column*/,
6068 GtkCellRenderer *cell,
6069 GtkTreeModel *tree_model,
6070 GtkTreeIter *iter,
6071 gpointer /*data*/)
6072 {
6073 gchar *family;
6074 gtk_tree_model_get(tree_model, iter, 0, &family, -1);
6075 gchar *const family_escaped = g_markup_escape_text(family, -1);
6077 static char const *const sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
6078 gchar *const sample_escaped = g_markup_escape_text(sample, -1);
6080 std::stringstream markup;
6081 markup << family_escaped << " <span foreground='darkgray' font_family='"
6082 << family_escaped << "'>" << sample_escaped << "</span>";
6083 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
6085 g_free(family);
6086 g_free(family_escaped);
6087 g_free(sample_escaped);
6088 }
6090 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
6091 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
6092 if (completion) {
6093 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
6094 g_object_unref (completion);
6095 }
6096 }
6098 GtkWidget*
6099 sp_text_toolbox_new (SPDesktop *desktop)
6100 {
6101 GtkToolbar *tbl = GTK_TOOLBAR(gtk_toolbar_new());
6102 GtkIconSize secondarySize = static_cast<GtkIconSize>(prefToSize("/toolbox/secondary", 1));
6104 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
6105 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
6107 GtkTooltips *tt = gtk_tooltips_new();
6108 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
6110 ////////////Family
6111 //Window
6112 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6113 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
6115 //Entry
6116 GtkWidget *entry = gtk_entry_new ();
6117 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
6118 GtkEntryCompletion *completion = gtk_entry_completion_new ();
6119 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
6120 gtk_entry_completion_set_text_column (completion, 0);
6121 gtk_entry_completion_set_minimum_key_length (completion, 1);
6122 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
6123 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
6124 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
6125 gtk_toolbar_append_widget( tbl, entry, "", "" );
6126 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
6128 //Button
6129 GtkWidget *button = gtk_button_new ();
6130 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
6131 gtk_toolbar_append_widget( tbl, button, "", "");
6133 //Popdown
6134 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
6135 GtkWidget *treeview = gtk_tree_view_new ();
6137 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
6138 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
6139 gtk_tree_view_column_pack_start (column, cell, FALSE);
6140 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
6141 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
6142 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
6144 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
6145 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
6146 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
6148 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
6150 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
6151 gtk_container_add (GTK_CONTAINER (sw), treeview);
6153 gtk_container_add (GTK_CONTAINER (window), sw);
6154 gtk_widget_set_size_request (window, 300, 450);
6156 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
6157 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
6158 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
6160 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
6162 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
6163 g_signal_connect (G_OBJECT (window), "focus-in-event", G_CALLBACK (sp_text_toolbox_popdown_focus_in), tbl);
6164 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
6166 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
6167 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
6169 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
6170 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
6171 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
6172 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
6173 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
6175 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, secondarySize);
6176 GtkWidget *box = gtk_event_box_new ();
6177 gtk_container_add (GTK_CONTAINER (box), image);
6178 gtk_toolbar_append_widget( tbl, box, "", "");
6179 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
6180 GtkTooltips *tooltips = gtk_tooltips_new ();
6181 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
6182 gtk_widget_hide (GTK_WIDGET (box));
6183 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
6185 ////////////Size
6186 gchar const *const sizes[] = {
6187 "4", "6", "8", "9", "10", "11", "12", "13", "14",
6188 "16", "18", "20", "22", "24", "28",
6189 "32", "36", "40", "48", "56", "64", "72", "144"
6190 };
6192 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
6193 for (unsigned int i = 0; i < G_N_ELEMENTS(sizes); ++i) {
6194 gtk_combo_box_append_text(GTK_COMBO_BOX(cbox), sizes[i]);
6195 }
6196 gtk_widget_set_size_request (cbox, 80, -1);
6197 gtk_toolbar_append_widget( tbl, cbox, "", "");
6198 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
6199 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
6200 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), tbl);
6201 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "focus-out-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_focusout), tbl);
6203 ////////////Text anchor
6204 GtkWidget *group = gtk_radio_button_new (NULL);
6205 GtkWidget *row = gtk_hbox_new (FALSE, 4);
6206 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
6208 // left
6209 GtkWidget *rbutton = group;
6210 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6211 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, secondarySize));
6212 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6214 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6215 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
6216 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
6217 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
6219 // center
6220 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
6221 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6222 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, secondarySize));
6223 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6225 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6226 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
6227 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
6228 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
6230 // right
6231 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
6232 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6233 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, secondarySize));
6234 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6236 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6237 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
6238 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
6239 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
6241 // fill
6242 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
6243 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6244 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, secondarySize));
6245 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6247 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6248 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
6249 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
6250 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
6252 gtk_toolbar_append_widget( tbl, row, "", "");
6254 //spacer
6255 gtk_toolbar_append_widget( tbl, gtk_vseparator_new(), "", "" );
6257 ////////////Text style
6258 row = gtk_hbox_new (FALSE, 4);
6260 // bold
6261 rbutton = gtk_toggle_button_new ();
6262 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6263 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, secondarySize));
6264 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6265 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
6267 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6268 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
6269 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
6271 // italic
6272 rbutton = gtk_toggle_button_new ();
6273 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6274 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, secondarySize));
6275 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6276 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
6278 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6279 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
6280 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
6282 gtk_toolbar_append_widget( tbl, row, "", "");
6284 //spacer
6285 gtk_toolbar_append_widget( tbl, gtk_vseparator_new(), "", "" );
6287 ////////////Text orientation
6288 group = gtk_radio_button_new (NULL);
6289 row = gtk_hbox_new (FALSE, 4);
6290 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
6292 // horizontal
6293 rbutton = group;
6294 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6295 gtk_container_add (GTK_CONTAINER (rbutton),
6296 sp_icon_new (static_cast<Inkscape::IconSize>(secondarySize), INKSCAPE_STOCK_WRITING_MODE_LR));
6297 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6298 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
6300 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6301 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
6302 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
6304 // vertical
6305 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
6306 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6307 gtk_container_add (GTK_CONTAINER (rbutton),
6308 sp_icon_new (static_cast<Inkscape::IconSize>(secondarySize), INKSCAPE_STOCK_WRITING_MODE_TB));
6309 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6310 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
6312 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6313 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
6314 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
6315 gtk_toolbar_append_widget( tbl, row, "", "" );
6318 //watch selection
6319 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
6321 sigc::connection *c_selection_changed =
6322 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
6323 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
6324 pool->add_connection ("selection-changed", c_selection_changed);
6326 sigc::connection *c_selection_modified =
6327 new sigc::connection (sp_desktop_selection (desktop)->connectModified
6328 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
6329 pool->add_connection ("selection-modified", c_selection_modified);
6331 sigc::connection *c_subselection_changed =
6332 new sigc::connection (desktop->connectToolSubselectionChanged
6333 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
6334 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
6336 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
6339 gtk_widget_show_all( GTK_WIDGET(tbl) );
6341 return GTK_WIDGET(tbl);
6342 } // end of sp_text_toolbox_new()
6344 }//<unnamed> namespace
6347 //#########################
6348 //## Connector ##
6349 //#########################
6351 static void sp_connector_path_set_avoid(void)
6352 {
6353 cc_selection_set_avoid(true);
6354 }
6357 static void sp_connector_path_set_ignore(void)
6358 {
6359 cc_selection_set_avoid(false);
6360 }
6364 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
6365 {
6366 // quit if run by the _changed callbacks
6367 if (g_object_get_data( tbl, "freeze" )) {
6368 return;
6369 }
6371 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
6372 SPDocument *doc = sp_desktop_document(desktop);
6374 if (!sp_document_get_undo_sensitive(doc))
6375 {
6376 return;
6377 }
6379 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
6381 if ( repr->attribute("inkscape:connector-spacing") ) {
6382 gdouble priorValue = gtk_adjustment_get_value(adj);
6383 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
6384 if ( priorValue == gtk_adjustment_get_value(adj) ) {
6385 return;
6386 }
6387 } else if ( adj->value == defaultConnSpacing ) {
6388 return;
6389 }
6391 // in turn, prevent callbacks from responding
6392 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
6394 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
6395 SP_OBJECT(desktop->namedview)->updateRepr();
6397 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
6398 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
6399 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
6400 Geom::Matrix m = Geom::identity();
6401 avoid_item_move(&m, item);
6402 }
6404 if (items) {
6405 g_slist_free(items);
6406 }
6408 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
6409 _("Change connector spacing"));
6411 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6413 spinbutton_defocus(GTK_OBJECT(tbl));
6414 }
6416 static void sp_connector_graph_layout(void)
6417 {
6418 if (!SP_ACTIVE_DESKTOP) return;
6419 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6421 // hack for clones, see comment in align-and-distribute.cpp
6422 int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
6423 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
6425 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
6427 prefs->setInt("/options/clonecompensation/value", saved_compensation);
6429 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
6430 }
6432 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
6433 {
6434 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6435 prefs->setBool("/tools/connector/directedlayout",
6436 gtk_toggle_action_get_active( act ));
6437 }
6439 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
6440 {
6441 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6442 prefs->setBool("/tools/connector/avoidoverlaplayout",
6443 gtk_toggle_action_get_active( act ));
6444 }
6447 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
6448 {
6449 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6450 prefs->setDouble("/tools/connector/length", adj->value);
6451 spinbutton_defocus(GTK_OBJECT(tbl));
6452 }
6454 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
6455 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
6456 bool /*is_interactive*/, gpointer data)
6457 {
6458 GtkWidget *tbl = GTK_WIDGET(data);
6460 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
6461 return;
6462 }
6463 if (strcmp(name, "inkscape:connector-spacing") != 0) {
6464 return;
6465 }
6467 GtkAdjustment *adj = (GtkAdjustment*)
6468 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
6469 gdouble spacing = defaultConnSpacing;
6470 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
6472 gtk_adjustment_set_value(adj, spacing);
6473 }
6476 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
6477 NULL, /* child_added */
6478 NULL, /* child_removed */
6479 connector_tb_event_attr_changed,
6480 NULL, /* content_changed */
6481 NULL /* order_changed */
6482 };
6485 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
6486 {
6487 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6488 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
6490 {
6491 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
6492 _("Avoid"),
6493 _("Make connectors avoid selected objects"),
6494 "connector_avoid",
6495 secondarySize );
6496 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
6497 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
6498 }
6500 {
6501 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
6502 _("Ignore"),
6503 _("Make connectors ignore selected objects"),
6504 "connector_ignore",
6505 secondarySize );
6506 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
6507 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
6508 }
6510 EgeAdjustmentAction* eact = 0;
6512 // Spacing spinbox
6513 eact = create_adjustment_action( "ConnectorSpacingAction",
6514 _("Connector Spacing"), _("Spacing:"),
6515 _("The amount of space left around objects by auto-routing connectors"),
6516 "/tools/connector/spacing", defaultConnSpacing,
6517 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
6518 0, 100, 1.0, 10.0,
6519 0, 0, 0,
6520 connector_spacing_changed, 1, 0 );
6521 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
6523 // Graph (connector network) layout
6524 {
6525 InkAction* inky = ink_action_new( "ConnectorGraphAction",
6526 _("Graph"),
6527 _("Nicely arrange selected connector network"),
6528 "graph_layout",
6529 secondarySize );
6530 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
6531 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
6532 }
6534 // Default connector length spinbox
6535 eact = create_adjustment_action( "ConnectorLengthAction",
6536 _("Connector Length"), _("Length:"),
6537 _("Ideal length for connectors when layout is applied"),
6538 "/tools/connector/length", 100,
6539 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
6540 10, 1000, 10.0, 100.0,
6541 0, 0, 0,
6542 connector_length_changed, 1, 0 );
6543 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
6546 // Directed edges toggle button
6547 {
6548 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
6549 _("Downwards"),
6550 _("Make connectors with end-markers (arrows) point downwards"),
6551 "directed_graph",
6552 Inkscape::ICON_SIZE_DECORATION );
6553 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
6555 bool tbuttonstate = prefs->getBool("/tools/connector/directedlayout");
6556 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE ));
6558 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
6559 }
6561 // Avoid overlaps toggle button
6562 {
6563 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
6564 _("Remove overlaps"),
6565 _("Do not allow overlapping shapes"),
6566 "remove_overlaps",
6567 Inkscape::ICON_SIZE_DECORATION );
6568 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
6570 bool tbuttonstate = prefs->getBool("/tools/connector/avoidoverlaplayout");
6571 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), (tbuttonstate ? TRUE : FALSE ));
6573 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
6574 }
6576 // Code to watch for changes to the connector-spacing attribute in
6577 // the XML.
6578 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
6579 g_assert(repr != NULL);
6581 purge_repr_listener( holder, holder );
6583 if (repr) {
6584 g_object_set_data( holder, "repr", repr );
6585 Inkscape::GC::anchor(repr);
6586 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
6587 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
6588 }
6589 } // end of sp_connector_toolbox_prep()
6592 //#########################
6593 //## Paintbucket ##
6594 //#########################
6596 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
6597 {
6598 gint channels = ege_select_one_action_get_active( act );
6599 flood_channels_set_channels( channels );
6600 }
6602 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
6603 {
6604 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6605 prefs->setInt("/tools/paintbucket/threshold", (gint)adj->value);
6606 }
6608 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
6609 {
6610 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6611 prefs->setBool("/tools/paintbucket/autogap", ege_select_one_action_get_active( act ));
6612 }
6614 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
6615 {
6616 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
6617 SPUnit const *unit = tracker->getActiveUnit();
6618 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6620 prefs->setDouble("/tools/paintbucket/offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
6621 prefs->setString("/tools/paintbucket/offsetunits", sp_unit_get_abbreviation(unit));
6622 }
6624 static void paintbucket_defaults (GtkWidget *, GObject *tbl)
6625 {
6626 // FIXME: make defaults settable via Inkscape Options
6627 struct KeyValue {
6628 char const *key;
6629 double value;
6630 } const key_values[] = {
6631 {"threshold", 15},
6632 {"offset", 0.0}
6633 };
6635 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
6636 KeyValue const &kv = key_values[i];
6637 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(tbl, kv.key));
6638 if ( adj ) {
6639 gtk_adjustment_set_value(adj, kv.value);
6640 }
6641 }
6643 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "channels_action" ) );
6644 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
6645 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "autogap_action" ) );
6646 ege_select_one_action_set_active( autogap_action, 0 );
6647 }
6649 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
6650 {
6651 EgeAdjustmentAction* eact = 0;
6652 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6654 {
6655 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
6657 GList* items = 0;
6658 gint count = 0;
6659 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
6660 {
6661 GtkTreeIter iter;
6662 gtk_list_store_append( model, &iter );
6663 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
6664 count++;
6665 }
6666 g_list_free( items );
6667 items = 0;
6668 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
6669 g_object_set( act1, "short_label", _("Fill by:"), NULL );
6670 ege_select_one_action_set_appearance( act1, "compact" );
6671 ege_select_one_action_set_active( act1, prefs->getInt("/tools/paintbucket/channels", 0) );
6672 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
6673 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
6674 g_object_set_data( holder, "channels_action", act1 );
6675 }
6677 // Spacing spinbox
6678 {
6679 eact = create_adjustment_action(
6680 "ThresholdAction",
6681 _("Fill Threshold"), _("Threshold:"),
6682 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
6683 "/tools/paintbucket/threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
6684 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 0.0,
6685 0, 0, 0,
6686 paintbucket_threshold_changed, 1, 0 );
6688 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
6689 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
6690 }
6692 // Create the units menu.
6693 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
6694 Glib::ustring stored_unit = prefs->getString("/tools/paintbucket/offsetunits");
6695 if (!stored_unit.empty())
6696 tracker->setActiveUnit(sp_unit_get_by_abbreviation(stored_unit.data()));
6697 g_object_set_data( holder, "tracker", tracker );
6698 {
6699 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
6700 gtk_action_group_add_action( mainActions, act );
6701 }
6703 // Offset spinbox
6704 {
6705 eact = create_adjustment_action(
6706 "OffsetAction",
6707 _("Grow/shrink by"), _("Grow/shrink by:"),
6708 _("The amount to grow (positive) or shrink (negative) the created fill path"),
6709 "/tools/paintbucket/offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
6710 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
6711 0, 0, 0,
6712 paintbucket_offset_changed, 1, 2);
6713 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
6715 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
6716 }
6718 /* Auto Gap */
6719 {
6720 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
6722 GList* items = 0;
6723 gint count = 0;
6724 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
6725 {
6726 GtkTreeIter iter;
6727 gtk_list_store_append( model, &iter );
6728 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
6729 count++;
6730 }
6731 g_list_free( items );
6732 items = 0;
6733 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
6734 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
6735 ege_select_one_action_set_appearance( act2, "compact" );
6736 ege_select_one_action_set_active( act2, prefs->getBool("/tools/paintbucket/autogap") );
6737 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
6738 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
6739 g_object_set_data( holder, "autogap_action", act2 );
6740 }
6742 /* Reset */
6743 {
6744 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
6745 _("Defaults"),
6746 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
6747 GTK_STOCK_CLEAR );
6748 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
6749 gtk_action_group_add_action( mainActions, act );
6750 gtk_action_set_sensitive( act, TRUE );
6751 }
6753 }
6755 /*
6756 Local Variables:
6757 mode:c++
6758 c-file-style:"stroustrup"
6759 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
6760 indent-tabs-mode:nil
6761 fill-column:99
6762 End:
6763 */
6764 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :