48e22d53f2895d742f6807836f8de9ba11eddfe1
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@users.sf.net>
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 "../conn-avoid-ref.h"
40 #include "../connection-pool.h"
41 #include "../connector-context.h"
42 #include "../desktop.h"
43 #include "../desktop-handles.h"
44 #include "../desktop-style.h"
45 #include "../dialogs/dialog-events.h"
46 #include "../dialogs/text-edit.h"
47 #include "../document-private.h"
48 #include "../ege-adjustment-action.h"
49 #include "../ege-output-action.h"
50 #include "../ege-select-one-action.h"
51 #include "../flood-context.h"
52 #include "gradient-toolbar.h"
53 #include "../graphlayout/graphlayout.h"
54 #include "../helper/unit-menu.h"
55 #include "../helper/units.h"
56 #include "../helper/unit-tracker.h"
57 #include "icon.h"
58 #include "../ink-action.h"
59 #include "../inkscape.h"
60 #include "../interface.h"
61 #include "../libnrtype/font-instance.h"
62 #include "../libnrtype/font-lister.h"
63 #include "../live_effects/effect.h"
64 #include "../live_effects/lpe-angle_bisector.h"
65 #include "../live_effects/lpe-line_segment.h"
66 #include "../lpe-tool-context.h"
67 #include "../mod360.h"
68 #include "../node-context.h"
69 #include "../pen-context.h"
70 #include "../preferences.h"
71 #include "../selection-chemistry.h"
72 #include "../selection.h"
73 #include "select-toolbar.h"
74 #include "../shape-editor.h"
75 #include "../shortcuts.h"
76 #include "../sp-clippath.h"
77 #include "../sp-ellipse.h"
78 #include "../sp-flowtext.h"
79 #include "../sp-mask.h"
80 #include "../sp-namedview.h"
81 #include "../sp-rect.h"
82 #include "../sp-spiral.h"
83 #include "../sp-star.h"
84 #include "../sp-text.h"
85 #include "../style.h"
86 #include "../svg/css-ostringstream.h"
87 #include "../tools-switch.h"
88 #include "../tweak-context.h"
89 #include "../spray-context.h"
90 #include "../ui/dialog/calligraphic-profile-rename.h"
91 #include "../ui/icon-names.h"
92 #include "../ui/widget/style-swatch.h"
93 #include "../verbs.h"
94 #include "../widgets/button.h"
95 #include "../widgets/spinbutton-events.h"
96 #include "../widgets/spw-utilities.h"
97 #include "../widgets/widget-sizes.h"
98 #include "../xml/attribute-record.h"
99 #include "../xml/node-event-vector.h"
100 #include "../xml/repr.h"
102 #include "toolbox.h"
104 using Inkscape::UnitTracker;
106 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
107 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
109 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
118 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
120 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
121 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
122 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
123 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
124 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
125 static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
126 static void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
128 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
131 Inkscape::IconSize prefToSize( Glib::ustring const &path, int base ) {
132 static Inkscape::IconSize sizeChoices[] = {
133 Inkscape::ICON_SIZE_LARGE_TOOLBAR,
134 Inkscape::ICON_SIZE_SMALL_TOOLBAR,
135 Inkscape::ICON_SIZE_MENU
136 };
137 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
138 int index = prefs->getIntLimited( path, base, 0, G_N_ELEMENTS(sizeChoices) );
139 return sizeChoices[index];
140 }
142 static struct {
143 gchar const *type_name;
144 gchar const *data_name;
145 sp_verb_t verb;
146 sp_verb_t doubleclick_verb;
147 } const tools[] = {
148 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
149 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
150 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
151 { "SPSprayContext", "spray_tool", SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS },
152 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
153 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
154 { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
155 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
156 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
157 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
158 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
159 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
160 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
161 { "SPLPEToolContext", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS },
162 { "SPEraserContext", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS },
163 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
164 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
165 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
166 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
167 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
168 { NULL, NULL, 0, 0 }
169 };
171 static struct {
172 gchar const *type_name;
173 gchar const *data_name;
174 GtkWidget *(*create_func)(SPDesktop *desktop);
175 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
176 gchar const *ui_name;
177 gint swatch_verb_id;
178 gchar const *swatch_tool;
179 gchar const *swatch_tip;
180 } const aux_toolboxes[] = {
181 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
182 SP_VERB_INVALID, 0, 0},
183 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
184 SP_VERB_INVALID, 0, 0},
185 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
186 SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")},
187 { "SPSprayContext", "spray_toolbox", 0, sp_spray_toolbox_prep, "SprayToolbar",
188 SP_VERB_CONTEXT_SPRAY_PREFS, "/tools/spray", N_("Color/opacity used for color spraying")},
189 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
190 SP_VERB_INVALID, 0, 0},
191 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
192 SP_VERB_CONTEXT_STAR_PREFS, "/tools/shapes/star", N_("Style of new stars")},
193 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
194 SP_VERB_CONTEXT_RECT_PREFS, "/tools/shapes/rect", N_("Style of new rectangles")},
195 { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar",
196 SP_VERB_CONTEXT_3DBOX_PREFS, "/tools/shapes/3dbox", N_("Style of new 3D boxes")},
197 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
198 SP_VERB_CONTEXT_ARC_PREFS, "/tools/shapes/arc", N_("Style of new ellipses")},
199 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
200 SP_VERB_CONTEXT_SPIRAL_PREFS, "/tools/shapes/spiral", N_("Style of new spirals")},
201 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
202 SP_VERB_CONTEXT_PENCIL_PREFS, "/tools/freehand/pencil", N_("Style of new paths created by Pencil")},
203 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
204 SP_VERB_CONTEXT_PEN_PREFS, "/tools/freehand/pen", N_("Style of new paths created by Pen")},
205 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
206 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "/tools/calligraphic", N_("Style of new calligraphic strokes")},
207 { "SPEraserContext", "eraser_toolbox", 0, sp_eraser_toolbox_prep,"EraserToolbar",
208 SP_VERB_CONTEXT_ERASER_PREFS, "/tools/eraser", _("TBD")},
209 { "SPLPEToolContext", "lpetool_toolbox", 0, sp_lpetool_toolbox_prep, "LPEToolToolbar",
210 SP_VERB_CONTEXT_LPETOOL_PREFS, "/tools/lpetool", _("TBD")},
211 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
212 SP_VERB_INVALID, 0, 0},
213 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
214 SP_VERB_INVALID, 0, 0},
215 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
216 SP_VERB_INVALID, 0, 0},
217 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
218 SP_VERB_INVALID, 0, 0},
219 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
220 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")},
221 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
222 };
224 #define TOOLBAR_SLIDER_HINT "full"
226 static gchar const * ui_descr =
227 "<ui>"
228 " <toolbar name='SelectToolbar'>"
229 " <toolitem action='EditSelectAll' />"
230 " <toolitem action='EditSelectAllInAllLayers' />"
231 " <toolitem action='EditDeselect' />"
232 " <separator />"
233 " <toolitem action='ObjectRotate90CCW' />"
234 " <toolitem action='ObjectRotate90' />"
235 " <toolitem action='ObjectFlipHorizontally' />"
236 " <toolitem action='ObjectFlipVertically' />"
237 " <separator />"
238 " <toolitem action='SelectionToBack' />"
239 " <toolitem action='SelectionLower' />"
240 " <toolitem action='SelectionRaise' />"
241 " <toolitem action='SelectionToFront' />"
242 " <separator />"
243 " <toolitem action='XAction' />"
244 " <toolitem action='YAction' />"
245 " <toolitem action='WidthAction' />"
246 " <toolitem action='LockAction' />"
247 " <toolitem action='HeightAction' />"
248 " <toolitem action='UnitsAction' />"
249 " <separator />"
250 " <toolitem action='transform_affect_label' />"
251 " <toolitem action='transform_stroke' />"
252 " <toolitem action='transform_corners' />"
253 " <toolitem action='transform_gradient' />"
254 " <toolitem action='transform_pattern' />"
255 " </toolbar>"
257 " <toolbar name='NodeToolbar'>"
258 " <toolitem action='NodeInsertAction' />"
259 " <toolitem action='NodeDeleteAction' />"
260 " <separator />"
261 " <toolitem action='NodeJoinAction' />"
262 " <toolitem action='NodeBreakAction' />"
263 " <separator />"
264 " <toolitem action='NodeJoinSegmentAction' />"
265 " <toolitem action='NodeDeleteSegmentAction' />"
266 " <separator />"
267 " <toolitem action='NodeCuspAction' />"
268 " <toolitem action='NodeSmoothAction' />"
269 " <toolitem action='NodeSymmetricAction' />"
270 " <toolitem action='NodeAutoAction' />"
271 " <separator />"
272 " <toolitem action='NodeLineAction' />"
273 " <toolitem action='NodeCurveAction' />"
274 " <separator />"
275 " <toolitem action='ObjectToPath' />"
276 " <toolitem action='StrokeToPath' />"
277 " <separator />"
278 " <toolitem action='NodeXAction' />"
279 " <toolitem action='NodeYAction' />"
280 " <toolitem action='NodeUnitsAction' />"
281 " <separator />"
282 " <toolitem action='ObjectEditClipPathAction' />"
283 " <toolitem action='ObjectEditMaskPathAction' />"
284 " <toolitem action='EditNextLPEParameterAction' />"
285 " <separator />"
286 " <toolitem action='NodesShowHandlesAction' />"
287 " <toolitem action='NodesShowHelperpath' />"
288 " </toolbar>"
290 " <toolbar name='TweakToolbar'>"
291 " <toolitem action='TweakWidthAction' />"
292 " <separator />"
293 " <toolitem action='TweakForceAction' />"
294 " <toolitem action='TweakPressureAction' />"
295 " <separator />"
296 " <toolitem action='TweakModeAction' />"
297 " <separator />"
298 " <toolitem action='TweakFidelityAction' />"
299 " <separator />"
300 " <toolitem action='TweakChannelsLabel' />"
301 " <toolitem action='TweakDoH' />"
302 " <toolitem action='TweakDoS' />"
303 " <toolitem action='TweakDoL' />"
304 " <toolitem action='TweakDoO' />"
305 " </toolbar>"
307 " <toolbar name='SprayToolbar'>"
308 " <toolitem action='SprayModeAction' />"
309 " <separator />"
310 " <toolitem action='SprayWidthAction' />"
311 " <separator />"
312 " <toolitem action='SprayPressureAction' />"
313 " <separator />"
314 " <toolitem action='SprayPopulationAction' />"
315 " <separator />"
316 " <toolitem action='SprayMeanAction' />"
317 " <toolitem action='SprayStandard_deviationAction' />"
318 " <separator />"
319 " <toolitem action='DialogSprayOption' />"
320 " </toolbar>"
322 " <toolbar name='ZoomToolbar'>"
323 " <toolitem action='ZoomIn' />"
324 " <toolitem action='ZoomOut' />"
325 " <separator />"
326 " <toolitem action='Zoom1:0' />"
327 " <toolitem action='Zoom1:2' />"
328 " <toolitem action='Zoom2:1' />"
329 " <separator />"
330 " <toolitem action='ZoomSelection' />"
331 " <toolitem action='ZoomDrawing' />"
332 " <toolitem action='ZoomPage' />"
333 " <toolitem action='ZoomPageWidth' />"
334 " <separator />"
335 " <toolitem action='ZoomPrev' />"
336 " <toolitem action='ZoomNext' />"
337 " </toolbar>"
339 " <toolbar name='StarToolbar'>"
340 " <separator />"
341 " <toolitem action='StarStateAction' />"
342 " <separator />"
343 " <toolitem action='FlatAction' />"
344 " <separator />"
345 " <toolitem action='MagnitudeAction' />"
346 " <toolitem action='SpokeAction' />"
347 " <toolitem action='RoundednessAction' />"
348 " <toolitem action='RandomizationAction' />"
349 " <separator />"
350 " <toolitem action='StarResetAction' />"
351 " </toolbar>"
353 " <toolbar name='RectToolbar'>"
354 " <toolitem action='RectStateAction' />"
355 " <toolitem action='RectWidthAction' />"
356 " <toolitem action='RectHeightAction' />"
357 " <toolitem action='RadiusXAction' />"
358 " <toolitem action='RadiusYAction' />"
359 " <toolitem action='RectUnitsAction' />"
360 " <separator />"
361 " <toolitem action='RectResetAction' />"
362 " </toolbar>"
364 " <toolbar name='3DBoxToolbar'>"
365 " <toolitem action='3DBoxAngleXAction' />"
366 " <toolitem action='3DBoxVPXStateAction' />"
367 " <separator />"
368 " <toolitem action='3DBoxAngleYAction' />"
369 " <toolitem action='3DBoxVPYStateAction' />"
370 " <separator />"
371 " <toolitem action='3DBoxAngleZAction' />"
372 " <toolitem action='3DBoxVPZStateAction' />"
373 " </toolbar>"
375 " <toolbar name='SpiralToolbar'>"
376 " <toolitem action='SpiralStateAction' />"
377 " <toolitem action='SpiralRevolutionAction' />"
378 " <toolitem action='SpiralExpansionAction' />"
379 " <toolitem action='SpiralT0Action' />"
380 " <separator />"
381 " <toolitem action='SpiralResetAction' />"
382 " </toolbar>"
384 " <toolbar name='PenToolbar'>"
385 " <toolitem action='FreehandModeActionPen' />"
386 " <separator />"
387 " <toolitem action='SetPenShapeAction'/>"
388 " </toolbar>"
390 " <toolbar name='PencilToolbar'>"
391 " <toolitem action='FreehandModeActionPencil' />"
392 " <separator />"
393 " <toolitem action='PencilToleranceAction' />"
394 " <separator />"
395 " <toolitem action='PencilResetAction' />"
396 " <separator />"
397 " <toolitem action='SetPencilShapeAction'/>"
398 " </toolbar>"
400 " <toolbar name='CalligraphyToolbar'>"
401 " <separator />"
402 " <toolitem action='SetProfileAction'/>"
403 " <separator />"
404 " <toolitem action='CalligraphyWidthAction' />"
405 " <toolitem action='PressureAction' />"
406 " <toolitem action='TraceAction' />"
407 " <toolitem action='ThinningAction' />"
408 " <separator />"
409 " <toolitem action='AngleAction' />"
410 " <toolitem action='TiltAction' />"
411 " <toolitem action='FixationAction' />"
412 " <separator />"
413 " <toolitem action='CapRoundingAction' />"
414 " <separator />"
415 " <toolitem action='TremorAction' />"
416 " <toolitem action='WiggleAction' />"
417 " <toolitem action='MassAction' />"
418 " <separator />"
419 " </toolbar>"
421 " <toolbar name='ArcToolbar'>"
422 " <toolitem action='ArcStateAction' />"
423 " <separator />"
424 " <toolitem action='ArcStartAction' />"
425 " <toolitem action='ArcEndAction' />"
426 " <separator />"
427 " <toolitem action='ArcOpenAction' />"
428 " <separator />"
429 " <toolitem action='ArcResetAction' />"
430 " <separator />"
431 " </toolbar>"
433 " <toolbar name='PaintbucketToolbar'>"
434 " <toolitem action='ChannelsAction' />"
435 " <separator />"
436 " <toolitem action='ThresholdAction' />"
437 " <separator />"
438 " <toolitem action='OffsetAction' />"
439 " <toolitem action='PaintbucketUnitsAction' />"
440 " <separator />"
441 " <toolitem action='AutoGapAction' />"
442 " <separator />"
443 " <toolitem action='PaintbucketResetAction' />"
444 " </toolbar>"
446 " <toolbar name='EraserToolbar'>"
447 " <toolitem action='EraserWidthAction' />"
448 " <separator />"
449 " <toolitem action='EraserModeAction' />"
450 " </toolbar>"
452 " <toolbar name='LPEToolToolbar'>"
453 " <toolitem action='LPEToolModeAction' />"
454 " <separator />"
455 " <toolitem action='LPEShowBBoxAction' />"
456 " <toolitem action='LPEBBoxFromSelectionAction' />"
457 " <separator />"
458 " <toolitem action='LPELineSegmentAction' />"
459 " <separator />"
460 " <toolitem action='LPEMeasuringAction' />"
461 " <toolitem action='LPEToolUnitsAction' />"
462 " <separator />"
463 " <toolitem action='LPEOpenLPEDialogAction' />"
464 " </toolbar>"
466 " <toolbar name='DropperToolbar'>"
467 " <toolitem action='DropperOpacityAction' />"
468 " <toolitem action='DropperPickAlphaAction' />"
469 " <toolitem action='DropperSetAlphaAction' />"
470 " </toolbar>"
472 " <toolbar name='ConnectorToolbar'>"
473 " <toolitem action='ConnectorEditModeAction' />"
474 " <toolitem action='ConnectorAvoidAction' />"
475 " <toolitem action='ConnectorIgnoreAction' />"
476 " <toolitem action='ConnectorOrthogonalAction' />"
477 " <toolitem action='ConnectorCurvatureAction' />"
478 " <toolitem action='ConnectorSpacingAction' />"
479 " <toolitem action='ConnectorGraphAction' />"
480 " <toolitem action='ConnectorLengthAction' />"
481 " <toolitem action='ConnectorDirectedAction' />"
482 " <toolitem action='ConnectorOverlapAction' />"
483 " <toolitem action='ConnectorNewConnPointAction' />"
484 " <toolitem action='ConnectorRemoveConnPointAction' />"
485 " </toolbar>"
487 "</ui>"
488 ;
490 static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop );
492 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
494 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
495 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
497 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
498 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
500 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
501 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
503 GtkWidget * sp_toolbox_button_new_from_verb_with_doubleclick( GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
504 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
505 Inkscape::UI::View::View *view, GtkTooltips *tt);
507 class VerbAction : public Gtk::Action {
508 public:
509 static Glib::RefPtr<VerbAction> create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
511 virtual ~VerbAction();
512 virtual void set_active(bool active = true);
514 protected:
515 virtual Gtk::Widget* create_menu_item_vfunc();
516 virtual Gtk::Widget* create_tool_item_vfunc();
518 virtual void connect_proxy_vfunc(Gtk::Widget* proxy);
519 virtual void disconnect_proxy_vfunc(Gtk::Widget* proxy);
521 virtual void on_activate();
523 private:
524 Inkscape::Verb* verb;
525 Inkscape::Verb* verb2;
526 Inkscape::UI::View::View *view;
527 GtkTooltips *tooltips;
528 bool active;
530 VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips);
531 };
534 Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips)
535 {
536 Glib::RefPtr<VerbAction> result;
537 SPAction *action = verb->get_action(view);
538 if ( action ) {
539 //SPAction* action2 = verb2 ? verb2->get_action(view) : 0;
540 result = Glib::RefPtr<VerbAction>(new VerbAction(verb, verb2, view, tooltips));
541 }
543 return result;
544 }
546 VerbAction::VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view, GtkTooltips *tooltips) :
547 Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(_(verb->get_name())), Glib::ustring(_(verb->get_tip()))),
548 verb(verb),
549 verb2(verb2),
550 view(view),
551 tooltips(tooltips),
552 active(false)
553 {
554 }
556 VerbAction::~VerbAction()
557 {
558 }
560 Gtk::Widget* VerbAction::create_menu_item_vfunc()
561 {
562 // First call in to get the icon rendered if present in SVG
563 Gtk::Widget *widget = sp_icon_get_icon( property_stock_id().get_value().get_string(), Inkscape::ICON_SIZE_MENU );
564 delete widget;
565 widget = 0;
567 Gtk::Widget* widg = Gtk::Action::create_menu_item_vfunc();
568 // g_message("create_menu_item_vfunc() = %p for '%s'", widg, verb->get_id());
569 return widg;
570 }
572 Gtk::Widget* VerbAction::create_tool_item_vfunc()
573 {
574 // Gtk::Widget* widg = Gtk::Action::create_tool_item_vfunc();
575 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/tools/small");
576 GtkWidget* toolbox = 0;
577 GtkWidget *button = sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
578 SP_BUTTON_TYPE_TOGGLE,
579 verb,
580 verb2,
581 view,
582 tooltips );
583 if ( active ) {
584 sp_button_toggle_set_down( SP_BUTTON(button), active);
585 }
586 gtk_widget_show_all( button );
587 Gtk::Widget* wrapped = Glib::wrap(button);
588 Gtk::ToolItem* holder = Gtk::manage(new Gtk::ToolItem());
589 holder->add(*wrapped);
591 // g_message("create_tool_item_vfunc() = %p for '%s'", holder, verb->get_id());
592 return holder;
593 }
595 void VerbAction::connect_proxy_vfunc(Gtk::Widget* proxy)
596 {
597 // g_message("connect_proxy_vfunc(%p) for '%s'", proxy, verb->get_id());
598 Gtk::Action::connect_proxy_vfunc(proxy);
599 }
601 void VerbAction::disconnect_proxy_vfunc(Gtk::Widget* proxy)
602 {
603 // g_message("disconnect_proxy_vfunc(%p) for '%s'", proxy, verb->get_id());
604 Gtk::Action::disconnect_proxy_vfunc(proxy);
605 }
607 void VerbAction::set_active(bool active)
608 {
609 this->active = active;
610 Glib::SListHandle<Gtk::Widget*> proxies = get_proxies();
611 for ( Glib::SListHandle<Gtk::Widget*>::iterator it = proxies.begin(); it != proxies.end(); ++it ) {
612 Gtk::ToolItem* ti = dynamic_cast<Gtk::ToolItem*>(*it);
613 if (ti) {
614 // *should* have one child that is the SPButton
615 Gtk::Widget* child = ti->get_child();
616 if ( child && SP_IS_BUTTON(child->gobj()) ) {
617 SPButton* button = SP_BUTTON(child->gobj());
618 sp_button_toggle_set_down( button, active );
619 }
620 }
621 }
622 }
624 void VerbAction::on_activate()
625 {
626 if ( verb ) {
627 SPAction *action = verb->get_action(view);
628 if ( action ) {
629 sp_action_perform(action, 0);
630 }
631 }
632 }
634 /* Global text entry widgets necessary for update */
635 /* GtkWidget *dropper_rgb_entry,
636 *dropper_opacity_entry ; */
637 // should be made a private member once this is converted to class
639 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
640 connection->disconnect();
641 delete connection;
642 }
644 static void purge_repr_listener( GObject* obj, GObject* tbl )
645 {
646 (void)obj;
647 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
648 if (oldrepr) { // remove old listener
649 sp_repr_remove_listener_by_data(oldrepr, tbl);
650 Inkscape::GC::release(oldrepr);
651 oldrepr = 0;
652 g_object_set_data( tbl, "repr", NULL );
653 }
654 }
656 GtkWidget *
657 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
658 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
659 Inkscape::UI::View::View *view, GtkTooltips *tt)
660 {
661 SPAction *action = verb->get_action(view);
662 if (!action) return NULL;
664 SPAction *doubleclick_action;
665 if (doubleclick_verb)
666 doubleclick_action = doubleclick_verb->get_action(view);
667 else
668 doubleclick_action = NULL;
670 /* fixme: Handle sensitive/unsensitive */
671 /* fixme: Implement sp_button_new_from_action */
672 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
673 gtk_widget_show(b);
676 unsigned int shortcut = sp_shortcut_get_primary(verb);
677 if (shortcut) {
678 gchar key[256];
679 sp_ui_shortcut_string(shortcut, key);
680 gchar *tip = g_strdup_printf ("%s (%s)", action->tip, key);
681 if ( t ) {
682 gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, tip, 0 );
683 }
684 g_free(tip);
685 } else {
686 if ( t ) {
687 gtk_toolbar_append_widget( GTK_TOOLBAR(t), b, action->tip, 0 );
688 }
689 }
691 return b;
692 }
695 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
696 {
697 SPAction* targetAction = SP_ACTION(user_data);
698 if ( targetAction ) {
699 sp_action_perform( targetAction, NULL );
700 }
701 }
703 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
704 {
705 if ( data ) {
706 GtkAction* act = GTK_ACTION(data);
707 gtk_action_set_sensitive( act, sensitive );
708 }
709 }
711 static SPActionEventVector action_event_vector = {
712 {NULL},
713 NULL,
714 NULL,
715 sp_action_action_set_sensitive,
716 NULL,
717 NULL
718 };
720 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
721 {
722 GtkAction* act = 0;
724 SPAction* targetAction = verb->get_action(view);
725 InkAction* inky = ink_action_new( verb->get_id(), _(verb->get_name()), verb->get_tip(), verb->get_image(), size );
726 act = GTK_ACTION(inky);
727 gtk_action_set_sensitive( act, targetAction->sensitive );
729 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
731 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
732 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
734 return act;
735 }
737 Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop )
738 {
739 Inkscape::UI::View::View *view = desktop;
740 gint verbsToUse[] = {
741 // disabled until we have icons for them:
742 //find
743 //SP_VERB_EDIT_TILE,
744 //SP_VERB_EDIT_UNTILE,
745 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
746 SP_VERB_DIALOG_SPRAY_OPTION,
747 SP_VERB_DIALOG_DISPLAY,
748 SP_VERB_DIALOG_FILL_STROKE,
749 SP_VERB_DIALOG_NAMEDVIEW,
750 SP_VERB_DIALOG_TEXT,
751 SP_VERB_DIALOG_XML_EDITOR,
752 SP_VERB_DIALOG_LAYERS,
753 SP_VERB_EDIT_CLONE,
754 SP_VERB_EDIT_COPY,
755 SP_VERB_EDIT_CUT,
756 SP_VERB_EDIT_DUPLICATE,
757 SP_VERB_EDIT_PASTE,
758 SP_VERB_EDIT_REDO,
759 SP_VERB_EDIT_UNDO,
760 SP_VERB_EDIT_UNLINK_CLONE,
761 SP_VERB_FILE_EXPORT,
762 SP_VERB_FILE_IMPORT,
763 SP_VERB_FILE_NEW,
764 SP_VERB_FILE_OPEN,
765 SP_VERB_FILE_PRINT,
766 SP_VERB_FILE_SAVE,
767 SP_VERB_OBJECT_TO_CURVE,
768 SP_VERB_SELECTION_GROUP,
769 SP_VERB_SELECTION_OUTLINE,
770 SP_VERB_SELECTION_UNGROUP,
771 SP_VERB_ZOOM_1_1,
772 SP_VERB_ZOOM_1_2,
773 SP_VERB_ZOOM_2_1,
774 SP_VERB_ZOOM_DRAWING,
775 SP_VERB_ZOOM_IN,
776 SP_VERB_ZOOM_NEXT,
777 SP_VERB_ZOOM_OUT,
778 SP_VERB_ZOOM_PAGE,
779 SP_VERB_ZOOM_PAGE_WIDTH,
780 SP_VERB_ZOOM_PREV,
781 SP_VERB_ZOOM_SELECTION,
782 };
784 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/small");
786 static std::map<SPDesktop*, Glib::RefPtr<Gtk::ActionGroup> > groups;
787 Glib::RefPtr<Gtk::ActionGroup> mainActions;
788 if ( groups.find(desktop) != groups.end() ) {
789 mainActions = groups[desktop];
790 }
792 if ( !mainActions ) {
793 mainActions = Gtk::ActionGroup::create("main");
794 groups[desktop] = mainActions;
795 }
797 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
798 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
799 if ( verb ) {
800 if (!mainActions->get_action(verb->get_id())) {
801 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
802 mainActions->add(Glib::wrap(act));
803 }
804 }
805 }
807 if ( !mainActions->get_action("ToolZoom") ) {
808 GtkTooltips *tt = gtk_tooltips_new();
809 for ( guint i = 0; i < G_N_ELEMENTS(tools) && tools[i].type_name; i++ ) {
810 Glib::RefPtr<VerbAction> va = VerbAction::create(Inkscape::Verb::get(tools[i].verb), Inkscape::Verb::get(tools[i].doubleclick_verb), view, tt);
811 if ( va ) {
812 mainActions->add(va);
813 if ( i == 0 ) {
814 va->set_active(true);
815 }
816 }
817 }
818 }
821 return mainActions;
822 }
825 void handlebox_detached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
826 {
827 gtk_widget_set_size_request( widget,
828 widget->allocation.width,
829 widget->allocation.height );
830 }
832 void handlebox_attached(GtkHandleBox* /*handlebox*/, GtkWidget* widget, gpointer /*userData*/)
833 {
834 gtk_widget_set_size_request( widget, -1, -1 );
835 }
839 GtkWidget *
840 sp_tool_toolbox_new()
841 {
842 GtkTooltips *tt = gtk_tooltips_new();
843 GtkWidget* tb = gtk_toolbar_new();
844 gtk_toolbar_set_orientation(GTK_TOOLBAR(tb), GTK_ORIENTATION_VERTICAL);
845 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(tb), TRUE);
847 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
848 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
850 gtk_widget_set_sensitive(tb, FALSE);
852 GtkWidget *hb = gtk_handle_box_new();
853 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
854 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
855 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
857 gtk_container_add(GTK_CONTAINER(hb), tb);
858 gtk_widget_show(GTK_WIDGET(tb));
860 sigc::connection* conn = new sigc::connection;
861 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
863 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
864 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
866 return hb;
867 }
869 GtkWidget *
870 sp_aux_toolbox_new()
871 {
872 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
874 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
876 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
878 gtk_widget_set_sensitive(tb, FALSE);
880 GtkWidget *hb = gtk_handle_box_new();
881 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
882 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
883 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
885 gtk_container_add(GTK_CONTAINER(hb), tb);
886 gtk_widget_show(GTK_WIDGET(tb));
888 sigc::connection* conn = new sigc::connection;
889 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
891 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
892 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
894 return hb;
895 }
897 //####################################
898 //# Commands Bar
899 //####################################
901 GtkWidget *
902 sp_commands_toolbox_new()
903 {
904 GtkWidget *tb = gtk_toolbar_new();
906 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
907 gtk_widget_set_sensitive(tb, FALSE);
909 GtkWidget *hb = gtk_handle_box_new();
910 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
911 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
912 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
914 gtk_container_add(GTK_CONTAINER(hb), tb);
915 gtk_widget_show(GTK_WIDGET(tb));
917 sigc::connection* conn = new sigc::connection;
918 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
920 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
921 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
923 return hb;
924 }
926 GtkWidget *
927 sp_snap_toolbox_new()
928 {
929 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
930 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
931 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
933 //GtkWidget *tb = gtk_toolbar_new();
934 //g_object_set_data(G_OBJECT(tb), "desktop", NULL);
936 gtk_widget_set_sensitive(tb, FALSE);
938 GtkWidget *hb = gtk_handle_box_new();
939 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
940 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
941 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
943 gtk_container_add(GTK_CONTAINER(hb), tb);
944 gtk_widget_show(GTK_WIDGET(tb));
946 sigc::connection* conn = new sigc::connection;
947 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
949 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(handlebox_detached), static_cast<gpointer>(0));
950 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(handlebox_attached), static_cast<gpointer>(0));
952 return hb;
953 }
955 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
956 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
957 Glib::ustring const &path, gdouble def,
958 GtkWidget *focusTarget,
959 GtkWidget *us,
960 GObject *dataKludge,
961 gboolean altx, gchar const *altx_mark,
962 gdouble lower, gdouble upper, gdouble step, gdouble page,
963 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
964 void (*callback)(GtkAdjustment *, GObject *),
965 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
966 {
967 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
968 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs->getDouble(path, def) * factor,
969 lower, upper, step, page, 0 ) );
970 if (us) {
971 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
972 }
974 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
976 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
977 if ( shortLabel ) {
978 g_object_set( act, "short_label", shortLabel, NULL );
979 }
981 if ( (descrCount > 0) && descrLabels && descrValues ) {
982 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
983 }
985 if ( focusTarget ) {
986 ege_adjustment_action_set_focuswidget( act, focusTarget );
987 }
989 if ( altx && altx_mark ) {
990 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
991 }
993 if ( dataKludge ) {
994 // Rather lame, but it's the only place where we need to get the entry name
995 // but we don't have an Entry
996 g_object_set_data( dataKludge, prefs->getEntry(path).getEntryName().data(), adj );
997 }
999 // Using a cast just to make sure we pass in the right kind of function pointer
1000 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
1002 return act;
1003 }
1006 //####################################
1007 //# node editing callbacks
1008 //####################################
1010 /**
1011 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
1012 */
1013 static ShapeEditor *get_current_shape_editor()
1014 {
1015 if (!SP_ACTIVE_DESKTOP) {
1016 return NULL;
1017 }
1019 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
1021 if (!SP_IS_NODE_CONTEXT(event_context)) {
1022 return NULL;
1023 }
1025 return event_context->shape_editor;
1026 }
1029 void
1030 sp_node_path_edit_add(void)
1031 {
1032 ShapeEditor *shape_editor = get_current_shape_editor();
1033 if (shape_editor) shape_editor->add_node();
1034 }
1036 void
1037 sp_node_path_edit_delete(void)
1038 {
1039 ShapeEditor *shape_editor = get_current_shape_editor();
1040 if (shape_editor) shape_editor->delete_nodes_preserving_shape();
1041 }
1043 void
1044 sp_node_path_edit_delete_segment(void)
1045 {
1046 ShapeEditor *shape_editor = get_current_shape_editor();
1047 if (shape_editor) shape_editor->delete_segment();
1048 }
1050 void
1051 sp_node_path_edit_break(void)
1052 {
1053 ShapeEditor *shape_editor = get_current_shape_editor();
1054 if (shape_editor) shape_editor->break_at_nodes();
1055 }
1057 void
1058 sp_node_path_edit_join(void)
1059 {
1060 ShapeEditor *shape_editor = get_current_shape_editor();
1061 if (shape_editor) shape_editor->join_nodes();
1062 }
1064 void
1065 sp_node_path_edit_join_segment(void)
1066 {
1067 ShapeEditor *shape_editor = get_current_shape_editor();
1068 if (shape_editor) shape_editor->join_segments();
1069 }
1071 void
1072 sp_node_path_edit_toline(void)
1073 {
1074 ShapeEditor *shape_editor = get_current_shape_editor();
1075 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
1076 }
1078 void
1079 sp_node_path_edit_tocurve(void)
1080 {
1081 ShapeEditor *shape_editor = get_current_shape_editor();
1082 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
1083 }
1085 void
1086 sp_node_path_edit_cusp(void)
1087 {
1088 ShapeEditor *shape_editor = get_current_shape_editor();
1089 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
1090 }
1092 void
1093 sp_node_path_edit_smooth(void)
1094 {
1095 ShapeEditor *shape_editor = get_current_shape_editor();
1096 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
1097 }
1099 void
1100 sp_node_path_edit_symmetrical(void)
1101 {
1102 ShapeEditor *shape_editor = get_current_shape_editor();
1103 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
1104 }
1106 void
1107 sp_node_path_edit_auto(void)
1108 {
1109 ShapeEditor *shape_editor = get_current_shape_editor();
1110 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_AUTO);
1111 }
1113 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
1114 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1115 bool show = gtk_toggle_action_get_active( act );
1116 prefs->setBool("/tools/nodes/show_handles", show);
1117 ShapeEditor *shape_editor = get_current_shape_editor();
1118 if (shape_editor) shape_editor->show_handles(show);
1119 }
1121 static void toggle_show_helperpath (GtkToggleAction *act, gpointer /*data*/) {
1122 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1123 bool show = gtk_toggle_action_get_active( act );
1124 prefs->setBool("/tools/nodes/show_helperpath", show);
1125 ShapeEditor *shape_editor = get_current_shape_editor();
1126 if (shape_editor) shape_editor->show_helperpath(show);
1127 }
1129 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
1130 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
1131 }
1133 void sp_node_path_edit_clippath (GtkAction */*act*/, gpointer data) {
1134 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), true);
1135 }
1137 void sp_node_path_edit_maskpath (GtkAction */*act*/, gpointer data) {
1138 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), false);
1139 }
1141 /* is called when the node selection is modified */
1142 static void
1143 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
1144 {
1145 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
1146 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
1147 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
1148 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
1150 // quit if run by the attr_changed listener
1151 if (g_object_get_data( tbl, "freeze" )) {
1152 return;
1153 }
1155 // in turn, prevent listener from responding
1156 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1158 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1159 SPUnit const *unit = tracker->getActiveUnit();
1161 ShapeEditor *shape_editor = get_current_shape_editor();
1162 if (shape_editor && shape_editor->has_nodepath()) {
1163 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
1164 int n_selected = 0;
1165 if (nodepath) {
1166 n_selected = nodepath->numSelected();
1167 }
1169 if (n_selected == 0) {
1170 gtk_action_set_sensitive(xact, FALSE);
1171 gtk_action_set_sensitive(yact, FALSE);
1172 } else {
1173 gtk_action_set_sensitive(xact, TRUE);
1174 gtk_action_set_sensitive(yact, TRUE);
1175 Geom::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
1176 Geom::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
1178 if (n_selected == 1) {
1179 Geom::Point sel_node = nodepath->singleSelectedCoords();
1180 if (oldx != sel_node[Geom::X] || oldy != sel_node[Geom::Y]) {
1181 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[Geom::X], *unit));
1182 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[Geom::Y], *unit));
1183 }
1184 } else {
1185 boost::optional<Geom::Coord> x = sp_node_selected_common_coord(nodepath, Geom::X);
1186 boost::optional<Geom::Coord> y = sp_node_selected_common_coord(nodepath, Geom::Y);
1187 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
1188 /* Note: Currently x and y will always have a value, even if the coordinates of the
1189 selected nodes don't coincide (in this case we use the coordinates of the center
1190 of the bounding box). So the entries are never set to zero. */
1191 // FIXME: Maybe we should clear the entry if several nodes are selected
1192 // instead of providing a kind of average value
1193 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
1194 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
1195 }
1196 }
1197 }
1198 } else {
1199 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
1200 gtk_action_set_sensitive(xact, FALSE);
1201 gtk_action_set_sensitive(yact, FALSE);
1202 }
1204 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1205 }
1207 static void
1208 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
1209 {
1210 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1211 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1213 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1214 SPUnit const *unit = tracker->getActiveUnit();
1216 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1217 prefs->setDouble(Glib::ustring("/tools/nodes/") + value_name, sp_units_get_pixels(adj->value, *unit));
1218 }
1220 // quit if run by the attr_changed listener
1221 if (g_object_get_data( tbl, "freeze" )) {
1222 return;
1223 }
1225 // in turn, prevent listener from responding
1226 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1228 ShapeEditor *shape_editor = get_current_shape_editor();
1229 if (shape_editor && shape_editor->has_nodepath()) {
1230 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
1231 if (!strcmp(value_name, "x")) {
1232 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, Geom::X);
1233 }
1234 if (!strcmp(value_name, "y")) {
1235 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, Geom::Y);
1236 }
1237 }
1239 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1240 }
1242 static void
1243 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
1244 {
1245 sp_node_path_value_changed(adj, tbl, "x");
1246 }
1248 static void
1249 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
1250 {
1251 sp_node_path_value_changed(adj, tbl, "y");
1252 }
1254 void
1255 sp_node_toolbox_sel_changed (Inkscape::Selection *selection, GObject *tbl)
1256 {
1257 {
1258 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_lpeedit" ) );
1259 SPItem *item = selection->singleItem();
1260 if (item && SP_IS_LPE_ITEM(item)) {
1261 if (sp_lpe_item_has_path_effect(SP_LPE_ITEM(item))) {
1262 gtk_action_set_sensitive(w, TRUE);
1263 } else {
1264 gtk_action_set_sensitive(w, FALSE);
1265 }
1266 } else {
1267 gtk_action_set_sensitive(w, FALSE);
1268 }
1269 }
1271 {
1272 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_clippathedit" ) );
1273 SPItem *item = selection->singleItem();
1274 if (item && item->clip_ref && item->clip_ref->getObject()) {
1275 gtk_action_set_sensitive(w, TRUE);
1276 } else {
1277 gtk_action_set_sensitive(w, FALSE);
1278 }
1279 }
1281 {
1282 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_maskedit" ) );
1283 SPItem *item = selection->singleItem();
1284 if (item && item->mask_ref && item->mask_ref->getObject()) {
1285 gtk_action_set_sensitive(w, TRUE);
1286 } else {
1287 gtk_action_set_sensitive(w, FALSE);
1288 }
1289 }
1290 }
1292 void
1293 sp_node_toolbox_sel_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
1294 {
1295 sp_node_toolbox_sel_changed (selection, tbl);
1296 }
1300 //################################
1301 //## Node Editing Toolbox ##
1302 //################################
1304 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1305 {
1306 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1307 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1308 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1309 g_object_set_data( holder, "tracker", tracker );
1311 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
1313 {
1314 InkAction* inky = ink_action_new( "NodeInsertAction",
1315 _("Insert node"),
1316 _("Insert new nodes into selected segments"),
1317 INKSCAPE_ICON_NODE_ADD,
1318 secondarySize );
1319 g_object_set( inky, "short_label", _("Insert"), NULL );
1320 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
1321 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1322 }
1324 {
1325 InkAction* inky = ink_action_new( "NodeDeleteAction",
1326 _("Delete node"),
1327 _("Delete selected nodes"),
1328 INKSCAPE_ICON_NODE_DELETE,
1329 secondarySize );
1330 g_object_set( inky, "short_label", _("Delete"), NULL );
1331 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
1332 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1333 }
1335 {
1336 InkAction* inky = ink_action_new( "NodeJoinAction",
1337 _("Join endnodes"),
1338 _("Join selected endnodes"),
1339 INKSCAPE_ICON_NODE_JOIN,
1340 secondarySize );
1341 g_object_set( inky, "short_label", _("Join"), NULL );
1342 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1343 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1344 }
1346 {
1347 InkAction* inky = ink_action_new( "NodeBreakAction",
1348 _("Break nodes"),
1349 _("Break path at selected nodes"),
1350 INKSCAPE_ICON_NODE_BREAK,
1351 secondarySize );
1352 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1353 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1354 }
1357 {
1358 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1359 _("Join with segment"),
1360 _("Join selected endnodes with a new segment"),
1361 INKSCAPE_ICON_NODE_JOIN_SEGMENT,
1362 secondarySize );
1363 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1364 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1365 }
1367 {
1368 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1369 _("Delete segment"),
1370 _("Delete segment between two non-endpoint nodes"),
1371 INKSCAPE_ICON_NODE_DELETE_SEGMENT,
1372 secondarySize );
1373 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1374 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1375 }
1377 {
1378 InkAction* inky = ink_action_new( "NodeCuspAction",
1379 _("Node Cusp"),
1380 _("Make selected nodes corner"),
1381 INKSCAPE_ICON_NODE_TYPE_CUSP,
1382 secondarySize );
1383 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1384 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1385 }
1387 {
1388 InkAction* inky = ink_action_new( "NodeSmoothAction",
1389 _("Node Smooth"),
1390 _("Make selected nodes smooth"),
1391 INKSCAPE_ICON_NODE_TYPE_SMOOTH,
1392 secondarySize );
1393 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1394 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1395 }
1397 {
1398 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1399 _("Node Symmetric"),
1400 _("Make selected nodes symmetric"),
1401 INKSCAPE_ICON_NODE_TYPE_SYMMETRIC,
1402 secondarySize );
1403 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1404 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1405 }
1407 {
1408 InkAction* inky = ink_action_new( "NodeAutoAction",
1409 _("Node Auto"),
1410 _("Make selected nodes auto-smooth"),
1411 INKSCAPE_ICON_NODE_TYPE_AUTO_SMOOTH,
1412 secondarySize );
1413 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_auto), 0 );
1414 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1415 }
1417 {
1418 InkAction* inky = ink_action_new( "NodeLineAction",
1419 _("Node Line"),
1420 _("Make selected segments lines"),
1421 INKSCAPE_ICON_NODE_SEGMENT_LINE,
1422 secondarySize );
1423 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1424 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1425 }
1427 {
1428 InkAction* inky = ink_action_new( "NodeCurveAction",
1429 _("Node Curve"),
1430 _("Make selected segments curves"),
1431 INKSCAPE_ICON_NODE_SEGMENT_CURVE,
1432 secondarySize );
1433 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1434 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1435 }
1437 {
1438 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1439 _("Show Handles"),
1440 _("Show the Bezier handles of selected nodes"),
1441 INKSCAPE_ICON_SHOW_NODE_HANDLES,
1442 Inkscape::ICON_SIZE_DECORATION );
1443 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1444 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1445 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/nodes/show_handles", true) );
1446 }
1448 {
1449 InkToggleAction* act = ink_toggle_action_new( "NodesShowHelperpath",
1450 _("Show Outline"),
1451 _("Show the outline of the path"),
1452 INKSCAPE_ICON_SHOW_PATH_OUTLINE,
1453 Inkscape::ICON_SIZE_DECORATION );
1454 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1455 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_helperpath), desktop );
1456 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/nodes/show_helperpath", false) );
1457 }
1459 {
1460 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1461 _("Next path effect parameter"),
1462 _("Show next path effect parameter for editing"),
1463 INKSCAPE_ICON_PATH_EFFECT_PARAMETER_NEXT,
1464 Inkscape::ICON_SIZE_DECORATION );
1465 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1466 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1467 g_object_set_data( holder, "nodes_lpeedit", inky);
1468 }
1470 {
1471 InkAction* inky = ink_action_new( "ObjectEditClipPathAction",
1472 _("Edit clipping path"),
1473 _("Edit the clipping path of the object"),
1474 INKSCAPE_ICON_PATH_CLIP_EDIT,
1475 Inkscape::ICON_SIZE_DECORATION );
1476 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_clippath), desktop );
1477 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1478 g_object_set_data( holder, "nodes_clippathedit", inky);
1479 }
1481 {
1482 InkAction* inky = ink_action_new( "ObjectEditMaskPathAction",
1483 _("Edit mask path"),
1484 _("Edit the mask of the object"),
1485 INKSCAPE_ICON_PATH_MASK_EDIT,
1486 Inkscape::ICON_SIZE_DECORATION );
1487 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_maskpath), desktop );
1488 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1489 g_object_set_data( holder, "nodes_maskedit", inky);
1490 }
1492 /* X coord of selected node(s) */
1493 {
1494 EgeAdjustmentAction* eact = 0;
1495 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1496 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1497 eact = create_adjustment_action( "NodeXAction",
1498 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1499 "/tools/nodes/Xcoord", 0,
1500 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1501 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1502 labels, values, G_N_ELEMENTS(labels),
1503 sp_node_path_x_value_changed );
1504 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1505 g_object_set_data( holder, "nodes_x_action", eact );
1506 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1507 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1508 }
1510 /* Y coord of selected node(s) */
1511 {
1512 EgeAdjustmentAction* eact = 0;
1513 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1514 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1515 eact = create_adjustment_action( "NodeYAction",
1516 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1517 "/tools/nodes/Ycoord", 0,
1518 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1519 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1520 labels, values, G_N_ELEMENTS(labels),
1521 sp_node_path_y_value_changed );
1522 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1523 g_object_set_data( holder, "nodes_y_action", eact );
1524 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1525 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1526 }
1528 // add the units menu
1529 {
1530 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1531 gtk_action_group_add_action( mainActions, act );
1532 }
1535 sp_node_toolbox_sel_changed(sp_desktop_selection(desktop), holder);
1537 //watch selection
1538 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
1540 sigc::connection *c_selection_changed =
1541 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
1542 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_changed), (GObject*)holder)));
1543 pool->add_connection ("selection-changed", c_selection_changed);
1545 sigc::connection *c_selection_modified =
1546 new sigc::connection (sp_desktop_selection (desktop)->connectModified
1547 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_modified), (GObject*)holder)));
1548 pool->add_connection ("selection-modified", c_selection_modified);
1550 sigc::connection *c_subselection_changed =
1551 new sigc::connection (desktop->connectToolSubselectionChanged
1552 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_coord_changed), (GObject*)holder)));
1553 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
1555 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool);
1557 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1558 } // end of sp_node_toolbox_prep()
1561 //########################
1562 //## Zoom Toolbox ##
1563 //########################
1565 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1566 {
1567 // no custom GtkAction setup needed
1568 } // end of sp_zoom_toolbox_prep()
1570 void
1571 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1572 {
1573 toolbox_set_desktop(toolbox,
1574 desktop,
1575 setup_tool_toolbox,
1576 update_tool_toolbox,
1577 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1578 "event_context_connection")));
1579 }
1582 void
1583 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1584 {
1585 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)),
1586 desktop,
1587 setup_aux_toolbox,
1588 update_aux_toolbox,
1589 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1590 "event_context_connection")));
1591 }
1593 void
1594 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1595 {
1596 toolbox_set_desktop(toolbox,
1597 desktop,
1598 setup_commands_toolbox,
1599 update_commands_toolbox,
1600 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1601 "event_context_connection")));
1602 }
1604 void
1605 sp_snap_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1606 {
1607 toolbox_set_desktop(toolbox,
1608 desktop,
1609 setup_snap_toolbox,
1610 update_snap_toolbox,
1611 static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox),
1612 "event_context_connection")));
1613 }
1616 static void
1617 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1618 {
1619 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1620 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1622 if (old_desktop) {
1623 GList *children, *iter;
1625 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1626 for ( iter = children ; iter ; iter = iter->next ) {
1627 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1628 }
1629 g_list_free(children);
1630 }
1632 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1634 if (desktop) {
1635 gtk_widget_set_sensitive(toolbox, TRUE);
1636 setup_func(toolbox, desktop);
1637 update_func(desktop, desktop->event_context, toolbox);
1638 *conn = desktop->connectEventContextChanged
1639 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1640 } else {
1641 gtk_widget_set_sensitive(toolbox, FALSE);
1642 }
1644 } // end of toolbox_set_desktop()
1647 static void
1648 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1649 {
1650 gchar const * descr =
1651 "<ui>"
1652 " <toolbar name='ToolToolbar'>"
1653 " <toolitem action='ToolSelector' />"
1654 " <toolitem action='ToolNode' />"
1655 " <toolitem action='ToolTweak' />"
1656 " <toolitem action='ToolSpray' />"
1657 " <toolitem action='ToolZoom' />"
1658 " <toolitem action='ToolRect' />"
1659 " <toolitem action='Tool3DBox' />"
1660 " <toolitem action='ToolArc' />"
1661 " <toolitem action='ToolStar' />"
1662 " <toolitem action='ToolSpiral' />"
1663 " <toolitem action='ToolPencil' />"
1664 " <toolitem action='ToolPen' />"
1665 " <toolitem action='ToolCalligraphic' />"
1666 " <toolitem action='ToolEraser' />"
1667 // " <toolitem action='ToolLPETool' />"
1668 " <toolitem action='ToolPaintBucket' />"
1669 " <toolitem action='ToolText' />"
1670 " <toolitem action='ToolConnector' />"
1671 " <toolitem action='ToolGradient' />"
1672 " <toolitem action='ToolDropper' />"
1673 " </toolbar>"
1674 "</ui>";
1675 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1676 GtkUIManager* mgr = gtk_ui_manager_new();
1677 GError* errVal = 0;
1678 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1680 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1681 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1683 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/ToolToolbar" );
1684 if ( prefs->getBool("/toolbox/icononly", true) ) {
1685 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1686 }
1687 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/tools/small");
1688 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1690 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_VERTICAL);
1691 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
1693 g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
1695 GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
1696 if ( child ) {
1697 gtk_container_remove( GTK_CONTAINER(toolbox), child );
1698 }
1700 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1701 // Inkscape::IconSize toolboxSize = prefToSize("/toolbox/tools/small");
1702 }
1705 static void
1706 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget */*toolbox*/ )
1707 {
1708 gchar const *const tname = ( eventcontext
1709 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1710 : NULL );
1711 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1713 for (int i = 0 ; tools[i].type_name ; i++ ) {
1714 Glib::RefPtr<Gtk::Action> act = mainActions->get_action( Inkscape::Verb::get(tools[i].verb)->get_id() );
1715 if ( act ) {
1716 bool setActive = tname && !strcmp(tname, tools[i].type_name);
1717 Glib::RefPtr<VerbAction> verbAct = Glib::RefPtr<VerbAction>::cast_dynamic(act);
1718 if ( verbAct ) {
1719 verbAct->set_active(setActive);
1720 }
1721 }
1722 }
1723 }
1725 static void
1726 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1727 {
1728 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1729 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1730 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1731 GtkUIManager* mgr = gtk_ui_manager_new();
1732 GError* errVal = 0;
1733 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1734 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1736 std::map<std::string, GtkWidget*> dataHolders;
1738 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1739 if ( aux_toolboxes[i].prep_func ) {
1740 // converted to GtkActions and UIManager
1742 GtkWidget* kludge = gtk_toolbar_new();
1743 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1744 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1745 dataHolders[aux_toolboxes[i].type_name] = kludge;
1746 aux_toolboxes[i].prep_func( desktop, mainActions->gobj(), G_OBJECT(kludge) );
1747 } else {
1749 GtkWidget *sub_toolbox = 0;
1750 if (aux_toolboxes[i].create_func == NULL)
1751 sub_toolbox = sp_empty_toolbox_new(desktop);
1752 else {
1753 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1754 }
1756 gtk_size_group_add_widget( grouper, sub_toolbox );
1758 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1759 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1761 }
1762 }
1764 // Second pass to create toolbars *after* all GtkActions are created
1765 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1766 if ( aux_toolboxes[i].prep_func ) {
1767 // converted to GtkActions and UIManager
1769 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1771 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1772 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1774 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1775 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1776 g_free( tmp );
1777 tmp = 0;
1779 if ( prefs->getBool( "/toolbox/icononly", true) ) {
1780 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1781 }
1783 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/small");
1784 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1786 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1788 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1789 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, _(aux_toolboxes[i].swatch_tip) );
1790 swatch->setDesktop( desktop );
1791 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1792 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1793 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1794 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 );
1795 }
1797 gtk_widget_show_all( holder );
1798 sp_set_font_size_smaller( holder );
1800 gtk_size_group_add_widget( grouper, holder );
1802 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1803 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1804 }
1805 }
1807 g_object_unref( G_OBJECT(grouper) );
1808 }
1810 static void
1811 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1812 {
1813 gchar const *tname = ( eventcontext
1814 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1815 : NULL );
1816 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1817 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1818 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1819 gtk_widget_show_all(sub_toolbox);
1820 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1821 } else {
1822 gtk_widget_hide(sub_toolbox);
1823 }
1824 }
1825 }
1827 static void
1828 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1829 {
1830 gchar const * descr =
1831 "<ui>"
1832 " <toolbar name='CommandsToolbar'>"
1833 " <toolitem action='FileNew' />"
1834 " <toolitem action='FileOpen' />"
1835 " <toolitem action='FileSave' />"
1836 " <toolitem action='FilePrint' />"
1837 " <separator />"
1838 " <toolitem action='FileImport' />"
1839 " <toolitem action='FileExport' />"
1840 " <separator />"
1841 " <toolitem action='EditUndo' />"
1842 " <toolitem action='EditRedo' />"
1843 " <separator />"
1844 " <toolitem action='EditCopy' />"
1845 " <toolitem action='EditCut' />"
1846 " <toolitem action='EditPaste' />"
1847 " <separator />"
1848 " <toolitem action='ZoomSelection' />"
1849 " <toolitem action='ZoomDrawing' />"
1850 " <toolitem action='ZoomPage' />"
1851 " <separator />"
1852 " <toolitem action='EditDuplicate' />"
1853 " <toolitem action='EditClone' />"
1854 " <toolitem action='EditUnlinkClone' />"
1855 " <separator />"
1856 " <toolitem action='SelectionGroup' />"
1857 " <toolitem action='SelectionUnGroup' />"
1858 " <separator />"
1859 " <toolitem action='DialogFillStroke' />"
1860 " <toolitem action='DialogText' />"
1861 " <toolitem action='DialogLayers' />"
1862 " <toolitem action='DialogXMLEditor' />"
1863 " <toolitem action='DialogAlignDistribute' />"
1864 " <separator />"
1865 " <toolitem action='DialogPreferences' />"
1866 " <toolitem action='DialogDocumentProperties' />"
1867 " </toolbar>"
1868 "</ui>";
1869 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop );
1870 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
1872 GtkUIManager* mgr = gtk_ui_manager_new();
1873 GError* errVal = 0;
1875 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
1876 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1878 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1879 if ( prefs->getBool("/toolbox/icononly", true) ) {
1880 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1881 }
1883 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/small");
1884 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1886 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_HORIZONTAL);
1887 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
1890 g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
1892 GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
1893 if ( child ) {
1894 gtk_container_remove( GTK_CONTAINER(toolbox), child );
1895 }
1897 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1898 }
1900 static void
1901 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1902 {
1903 }
1905 void toggle_snap_callback (GtkToggleAction *act, gpointer data) { //data points to the toolbox
1907 if (g_object_get_data(G_OBJECT(data), "freeze" )) {
1908 return;
1909 }
1911 gpointer ptr = g_object_get_data(G_OBJECT(data), "desktop");
1912 g_assert(ptr != NULL);
1914 SPDesktop *dt = reinterpret_cast<SPDesktop*>(ptr);
1915 SPNamedView *nv = sp_desktop_namedview(dt);
1916 SPDocument *doc = SP_OBJECT_DOCUMENT(nv);
1918 if (dt == NULL || nv == NULL) {
1919 g_warning("No desktop or namedview specified (in toggle_snap_callback)!");
1920 return;
1921 }
1923 Inkscape::XML::Node *repr = SP_OBJECT_REPR(nv);
1925 if (repr == NULL) {
1926 g_warning("This namedview doesn't have a xml representation attached!");
1927 return;
1928 }
1930 bool saved = sp_document_get_undo_sensitive(doc);
1931 sp_document_set_undo_sensitive(doc, false);
1933 bool v = false;
1934 SPAttributeEnum attr = (SPAttributeEnum) GPOINTER_TO_INT(g_object_get_data(G_OBJECT(act), "SP_ATTR_INKSCAPE"));
1936 switch (attr) {
1937 case SP_ATTR_INKSCAPE_SNAP_GLOBAL:
1938 dt->toggleSnapGlobal();
1939 break;
1940 case SP_ATTR_INKSCAPE_SNAP_BBOX:
1941 v = nv->snap_manager.snapprefs.getSnapModeBBox();
1942 sp_repr_set_boolean(repr, "inkscape:snap-bbox", !v);
1943 break;
1944 case SP_ATTR_INKSCAPE_BBOX_PATHS:
1945 v = nv->snap_manager.snapprefs.getSnapToBBoxPath();
1946 sp_repr_set_boolean(repr, "inkscape:bbox-paths", !v);
1947 break;
1948 case SP_ATTR_INKSCAPE_BBOX_NODES:
1949 v = nv->snap_manager.snapprefs.getSnapToBBoxNode();
1950 sp_repr_set_boolean(repr, "inkscape:bbox-nodes", !v);
1951 break;
1952 case SP_ATTR_INKSCAPE_SNAP_NODES:
1953 v = nv->snap_manager.snapprefs.getSnapModeNode();
1954 sp_repr_set_boolean(repr, "inkscape:snap-nodes", !v);
1955 break;
1956 case SP_ATTR_INKSCAPE_OBJECT_PATHS:
1957 v = nv->snap_manager.snapprefs.getSnapToItemPath();
1958 sp_repr_set_boolean(repr, "inkscape:object-paths", !v);
1959 break;
1960 case SP_ATTR_INKSCAPE_OBJECT_NODES:
1961 v = nv->snap_manager.snapprefs.getSnapToItemNode();
1962 sp_repr_set_boolean(repr, "inkscape:object-nodes", !v);
1963 break;
1964 case SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES:
1965 v = nv->snap_manager.snapprefs.getSnapSmoothNodes();
1966 sp_repr_set_boolean(repr, "inkscape:snap-smooth-nodes", !v);
1967 break;
1968 case SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS:
1969 v = nv->snap_manager.snapprefs.getSnapIntersectionCS();
1970 sp_repr_set_boolean(repr, "inkscape:snap-intersection-paths", !v);
1971 break;
1972 case SP_ATTR_INKSCAPE_SNAP_CENTER:
1973 v = nv->snap_manager.snapprefs.getIncludeItemCenter();
1974 sp_repr_set_boolean(repr, "inkscape:snap-center", !v);
1975 break;
1976 case SP_ATTR_INKSCAPE_SNAP_GRIDS:
1977 v = nv->snap_manager.snapprefs.getSnapToGrids();
1978 sp_repr_set_boolean(repr, "inkscape:snap-grids", !v);
1979 break;
1980 case SP_ATTR_INKSCAPE_SNAP_TO_GUIDES:
1981 v = nv->snap_manager.snapprefs.getSnapToGuides();
1982 sp_repr_set_boolean(repr, "inkscape:snap-to-guides", !v);
1983 break;
1984 case SP_ATTR_INKSCAPE_SNAP_PAGE:
1985 v = nv->snap_manager.snapprefs.getSnapToPageBorder();
1986 sp_repr_set_boolean(repr, "inkscape:snap-page", !v);
1987 break;
1988 /*case SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE:
1989 v = nv->snap_manager.snapprefs.getSnapIntersectionGG();
1990 sp_repr_set_boolean(repr, "inkscape:snap-intersection-grid-guide", !v);
1991 break;*/
1992 case SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS:
1993 v = nv->snap_manager.snapprefs.getSnapLineMidpoints();
1994 sp_repr_set_boolean(repr, "inkscape:snap-midpoints", !v);
1995 break;
1996 case SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS:
1997 v = nv->snap_manager.snapprefs.getSnapObjectMidpoints();
1998 sp_repr_set_boolean(repr, "inkscape:snap-object-midpoints", !v);
1999 break;
2000 case SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS:
2001 v = nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints();
2002 sp_repr_set_boolean(repr, "inkscape:snap-bbox-edge-midpoints", !v);
2003 break;
2004 case SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS:
2005 v = nv->snap_manager.snapprefs.getSnapBBoxMidpoints();
2006 sp_repr_set_boolean(repr, "inkscape:snap-bbox-midpoints", !v);
2007 break;
2008 default:
2009 g_warning("toggle_snap_callback has been called with an ID for which no action has been defined");
2010 break;
2011 }
2013 // The snapping preferences are stored in the document, and therefore toggling makes the document dirty
2014 doc->setModifiedSinceSave();
2016 sp_document_set_undo_sensitive(doc, saved);
2017 }
2019 void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
2020 {
2021 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2022 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
2024 gchar const * descr =
2025 "<ui>"
2026 " <toolbar name='SnapToolbar'>"
2027 " <toolitem action='ToggleSnapGlobal' />"
2028 " <separator />"
2029 " <toolitem action='ToggleSnapFromBBoxCorner' />"
2030 " <toolitem action='ToggleSnapToBBoxPath' />"
2031 " <toolitem action='ToggleSnapToBBoxNode' />"
2032 " <toolitem action='ToggleSnapToFromBBoxEdgeMidpoints' />"
2033 " <toolitem action='ToggleSnapToFromBBoxCenters' />"
2034 " <separator />"
2035 " <toolitem action='ToggleSnapFromNode' />"
2036 " <toolitem action='ToggleSnapToItemPath' />"
2037 " <toolitem action='ToggleSnapToPathIntersections' />"
2038 " <toolitem action='ToggleSnapToItemNode' />"
2039 " <toolitem action='ToggleSnapToSmoothNodes' />"
2040 " <toolitem action='ToggleSnapToFromLineMidpoints' />"
2041 " <toolitem action='ToggleSnapToFromObjectCenters' />"
2042 " <toolitem action='ToggleSnapToFromRotationCenter' />"
2043 " <separator />"
2044 " <toolitem action='ToggleSnapToPageBorder' />"
2045 " <toolitem action='ToggleSnapToGrids' />"
2046 " <toolitem action='ToggleSnapToGuides' />"
2047 //" <toolitem action='ToggleSnapToGridGuideIntersections' />"
2048 " </toolbar>"
2049 "</ui>";
2051 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
2053 {
2054 InkToggleAction* act = ink_toggle_action_new("ToggleSnapGlobal",
2055 _("Snap"), _("Enable snapping"), INKSCAPE_ICON_SNAP, secondarySize,
2056 SP_ATTR_INKSCAPE_SNAP_GLOBAL);
2058 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2059 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2060 }
2062 {
2063 InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromBBoxCorner",
2064 _("Bounding box"), _("Snap bounding box corners"), INKSCAPE_ICON_SNAP_BOUNDING_BOX,
2065 secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX);
2067 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2068 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2069 }
2071 {
2072 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxPath",
2073 _("Bounding box edges"), _("Snap to edges of a bounding box"),
2074 INKSCAPE_ICON_SNAP_BOUNDING_BOX_EDGES, secondarySize, SP_ATTR_INKSCAPE_BBOX_PATHS);
2076 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2077 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2078 }
2080 {
2081 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToBBoxNode",
2082 _("Bounding box corners"), _("Snap to bounding box corners"),
2083 INKSCAPE_ICON_SNAP_BOUNDING_BOX_CORNERS, secondarySize, SP_ATTR_INKSCAPE_BBOX_NODES);
2085 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2086 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2087 }
2089 {
2090 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxEdgeMidpoints",
2091 _("BBox Edge Midpoints"), _("Snap from and to midpoints of bounding box edges"),
2092 INKSCAPE_ICON_SNAP_BOUNDING_BOX_MIDPOINTS, secondarySize,
2093 SP_ATTR_INKSCAPE_SNAP_BBOX_EDGE_MIDPOINTS);
2095 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2096 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2097 }
2099 {
2100 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromBBoxCenters",
2101 _("BBox Centers"), _("Snapping from and to centers of bounding boxes"),
2102 INKSCAPE_ICON_SNAP_BOUNDING_BOX_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_BBOX_MIDPOINTS);
2104 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2105 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2106 }
2108 {
2109 InkToggleAction* act = ink_toggle_action_new("ToggleSnapFromNode",
2110 _("Nodes"), _("Snap nodes or handles"), INKSCAPE_ICON_SNAP_NODES, secondarySize, SP_ATTR_INKSCAPE_SNAP_NODES);
2112 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2113 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2114 }
2116 {
2117 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemPath",
2118 _("Paths"), _("Snap to paths"), INKSCAPE_ICON_SNAP_NODES_PATH, secondarySize,
2119 SP_ATTR_INKSCAPE_OBJECT_PATHS);
2121 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2122 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2123 }
2125 {
2126 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPathIntersections",
2127 _("Path intersections"), _("Snap to path intersections"),
2128 INKSCAPE_ICON_SNAP_NODES_INTERSECTION, secondarySize, SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS);
2130 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2131 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2132 }
2134 {
2135 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToItemNode",
2136 _("To nodes"), _("Snap to cusp nodes"), INKSCAPE_ICON_SNAP_NODES_CUSP, secondarySize,
2137 SP_ATTR_INKSCAPE_OBJECT_NODES);
2139 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2140 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2141 }
2143 {
2144 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToSmoothNodes",
2145 _("Smooth nodes"), _("Snap to smooth nodes"), INKSCAPE_ICON_SNAP_NODES_SMOOTH,
2146 secondarySize, SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES);
2148 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2149 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2150 }
2152 {
2153 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromLineMidpoints",
2154 _("Line Midpoints"), _("Snap from and to midpoints of line segments"),
2155 INKSCAPE_ICON_SNAP_NODES_MIDPOINT, secondarySize, SP_ATTR_INKSCAPE_SNAP_LINE_MIDPOINTS);
2157 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2158 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2159 }
2161 {
2162 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromObjectCenters",
2163 _("Object Centers"), _("Snap from and to centers of objects"),
2164 INKSCAPE_ICON_SNAP_NODES_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_OBJECT_MIDPOINTS);
2166 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2167 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2168 }
2170 {
2171 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToFromRotationCenter",
2172 _("Rotation Centers"), _("Snap from and to an item's rotation center"),
2173 INKSCAPE_ICON_SNAP_NODES_ROTATION_CENTER, secondarySize, SP_ATTR_INKSCAPE_SNAP_CENTER);
2175 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2176 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2177 }
2179 {
2180 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToPageBorder",
2181 _("Page border"), _("Snap to the page border"), INKSCAPE_ICON_SNAP_PAGE,
2182 secondarySize, SP_ATTR_INKSCAPE_SNAP_PAGE);
2184 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2185 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2186 }
2188 {
2189 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGrids",
2190 _("Grids"), _("Snap to grids"), INKSCAPE_ICON_GRID_RECTANGULAR, secondarySize,
2191 SP_ATTR_INKSCAPE_SNAP_GRIDS);
2193 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2194 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2195 }
2197 {
2198 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGuides",
2199 _("Guides"), _("Snap to guides"), INKSCAPE_ICON_GUIDES, secondarySize,
2200 SP_ATTR_INKSCAPE_SNAP_TO_GUIDES);
2202 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2203 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2204 }
2206 /*{
2207 InkToggleAction* act = ink_toggle_action_new("ToggleSnapToGridGuideIntersections",
2208 _("Grid/guide intersections"), _("Snap to intersections of a grid with a guide"),
2209 INKSCAPE_ICON_SNAP_GRID_GUIDE_INTERSECTIONS, secondarySize,
2210 SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE);
2212 gtk_action_group_add_action( mainActions->gobj(), GTK_ACTION( act ) );
2213 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_snap_callback), toolbox );
2214 }*/
2216 GtkUIManager* mgr = gtk_ui_manager_new();
2217 GError* errVal = 0;
2219 gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 );
2220 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
2222 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/SnapToolbar" );
2223 if ( prefs->getBool("/toolbox/icononly", true) ) {
2224 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
2225 }
2227 Inkscape::IconSize toolboxSize = prefToSize("/toolbox/secondary");
2228 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
2230 gtk_toolbar_set_orientation(GTK_TOOLBAR(toolBar), GTK_ORIENTATION_HORIZONTAL);
2231 gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE);
2233 g_object_set_data(G_OBJECT(toolBar), "desktop", NULL);
2235 GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox));
2236 if ( child ) {
2237 gtk_container_remove( GTK_CONTAINER(toolbox), child );
2238 }
2240 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
2242 }
2244 void update_snap_toolbox(SPDesktop *desktop, SPEventContext */*eventcontext*/, GtkWidget *toolbox)
2245 {
2246 g_assert(desktop != NULL);
2247 g_assert(toolbox != NULL);
2249 SPNamedView *nv = sp_desktop_namedview(desktop);
2250 if (nv == NULL) {
2251 g_warning("Namedview cannot be retrieved (in update_snap_toolbox)!");
2252 return;
2253 }
2255 Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions(desktop);
2257 Glib::RefPtr<Gtk::Action> act1 = mainActions->get_action("ToggleSnapGlobal");
2258 Glib::RefPtr<Gtk::Action> act2 = mainActions->get_action("ToggleSnapFromBBoxCorner");
2259 Glib::RefPtr<Gtk::Action> act3 = mainActions->get_action("ToggleSnapToBBoxPath");
2260 Glib::RefPtr<Gtk::Action> act4 = mainActions->get_action("ToggleSnapToBBoxNode");
2261 Glib::RefPtr<Gtk::Action> act4b = mainActions->get_action("ToggleSnapToFromBBoxEdgeMidpoints");
2262 Glib::RefPtr<Gtk::Action> act4c = mainActions->get_action("ToggleSnapToFromBBoxCenters");
2263 Glib::RefPtr<Gtk::Action> act5 = mainActions->get_action("ToggleSnapFromNode");
2264 Glib::RefPtr<Gtk::Action> act6 = mainActions->get_action("ToggleSnapToItemPath");
2265 Glib::RefPtr<Gtk::Action> act6b = mainActions->get_action("ToggleSnapToPathIntersections");
2266 Glib::RefPtr<Gtk::Action> act7 = mainActions->get_action("ToggleSnapToItemNode");
2267 Glib::RefPtr<Gtk::Action> act8 = mainActions->get_action("ToggleSnapToSmoothNodes");
2268 Glib::RefPtr<Gtk::Action> act9 = mainActions->get_action("ToggleSnapToFromLineMidpoints");
2269 Glib::RefPtr<Gtk::Action> act10 = mainActions->get_action("ToggleSnapToFromObjectCenters");
2270 Glib::RefPtr<Gtk::Action> act11 = mainActions->get_action("ToggleSnapToFromRotationCenter");
2271 Glib::RefPtr<Gtk::Action> act12 = mainActions->get_action("ToggleSnapToPageBorder");
2272 //Glib::RefPtr<Gtk::Action> act13 = mainActions->get_action("ToggleSnapToGridGuideIntersections");
2273 Glib::RefPtr<Gtk::Action> act14 = mainActions->get_action("ToggleSnapToGrids");
2274 Glib::RefPtr<Gtk::Action> act15 = mainActions->get_action("ToggleSnapToGuides");
2277 if (!act1) {
2278 return; // The snap actions haven't been defined yet (might be the case during startup)
2279 }
2281 // The ..._set_active calls below will toggle the buttons, but this shouldn't lead to
2282 // changes in our document because we're only updating the UI;
2283 // Setting the "freeze" parameter to true will block the code in toggle_snap_callback()
2284 g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(TRUE));
2286 bool const c1 = nv->snap_manager.snapprefs.getSnapEnabledGlobally();
2287 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act1->gobj()), c1);
2289 bool const c2 = nv->snap_manager.snapprefs.getSnapModeBBox();
2290 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act2->gobj()), c2);
2291 gtk_action_set_sensitive(GTK_ACTION(act2->gobj()), c1);
2293 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act3->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxPath());
2294 gtk_action_set_sensitive(GTK_ACTION(act3->gobj()), c1 && c2);
2295 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4->gobj()), nv->snap_manager.snapprefs.getSnapToBBoxNode());
2296 gtk_action_set_sensitive(GTK_ACTION(act4->gobj()), c1 && c2);
2297 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4b->gobj()), nv->snap_manager.snapprefs.getSnapBBoxEdgeMidpoints());
2298 gtk_action_set_sensitive(GTK_ACTION(act4b->gobj()), c1 && c2);
2299 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act4c->gobj()), nv->snap_manager.snapprefs.getSnapBBoxMidpoints());
2300 gtk_action_set_sensitive(GTK_ACTION(act4c->gobj()), c1 && c2);
2302 bool const c3 = nv->snap_manager.snapprefs.getSnapModeNode();
2303 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act5->gobj()), c3);
2304 gtk_action_set_sensitive(GTK_ACTION(act5->gobj()), c1);
2306 bool const c4 = nv->snap_manager.snapprefs.getSnapToItemPath();
2307 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6->gobj()), c4);
2308 gtk_action_set_sensitive(GTK_ACTION(act6->gobj()), c1 && c3);
2309 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act6b->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionCS());
2310 gtk_action_set_sensitive(GTK_ACTION(act6b->gobj()), c1 && c3 && c4);
2311 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act7->gobj()), nv->snap_manager.snapprefs.getSnapToItemNode());
2312 gtk_action_set_sensitive(GTK_ACTION(act7->gobj()), c1 && c3);
2313 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act8->gobj()), nv->snap_manager.snapprefs.getSnapSmoothNodes());
2314 gtk_action_set_sensitive(GTK_ACTION(act8->gobj()), c1 && c3);
2315 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act9->gobj()), nv->snap_manager.snapprefs.getSnapLineMidpoints());
2316 gtk_action_set_sensitive(GTK_ACTION(act9->gobj()), c1 && c3);
2317 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act10->gobj()), nv->snap_manager.snapprefs.getSnapObjectMidpoints());
2318 gtk_action_set_sensitive(GTK_ACTION(act10->gobj()), c1 && c3);
2319 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act11->gobj()), nv->snap_manager.snapprefs.getIncludeItemCenter());
2320 gtk_action_set_sensitive(GTK_ACTION(act11->gobj()), c1 && c3);
2322 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act12->gobj()), nv->snap_manager.snapprefs.getSnapToPageBorder());
2323 gtk_action_set_sensitive(GTK_ACTION(act12->gobj()), c1);
2324 //gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act13->gobj()), nv->snap_manager.snapprefs.getSnapIntersectionGG());
2325 //gtk_action_set_sensitive(GTK_ACTION(act13->gobj()), c1);
2327 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act14->gobj()), nv->snap_manager.snapprefs.getSnapToGrids());
2328 gtk_action_set_sensitive(GTK_ACTION(act14->gobj()), c1);
2329 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act15->gobj()), nv->snap_manager.snapprefs.getSnapToGuides());
2330 gtk_action_set_sensitive(GTK_ACTION(act15->gobj()), c1);
2333 g_object_set_data(G_OBJECT(toolbox), "freeze", GINT_TO_POINTER(FALSE)); // unfreeze (see above)
2334 }
2336 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
2337 {
2338 gtk_widget_show(toolbox_toplevel);
2339 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
2341 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
2342 if (!shown_toolbox) {
2343 return;
2344 }
2345 gtk_widget_show(toolbox);
2347 gtk_widget_show_all(shown_toolbox);
2348 }
2350 static GtkWidget *
2351 sp_empty_toolbox_new(SPDesktop *desktop)
2352 {
2353 GtkWidget *tbl = gtk_toolbar_new();
2354 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
2355 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
2357 gtk_widget_show_all(tbl);
2358 sp_set_font_size_smaller (tbl);
2360 return tbl;
2361 }
2363 #define MODE_LABEL_WIDTH 70
2365 //########################
2366 //## Star ##
2367 //########################
2369 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
2370 {
2371 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2373 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2374 // do not remember prefs if this call is initiated by an undo change, because undoing object
2375 // creation sets bogus values to its attributes before it is deleted
2376 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2377 prefs->setInt("/tools/shapes/star/magnitude", (gint)adj->value);
2378 }
2380 // quit if run by the attr_changed listener
2381 if (g_object_get_data( dataKludge, "freeze" )) {
2382 return;
2383 }
2385 // in turn, prevent listener from responding
2386 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2388 bool modmade = false;
2390 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2391 GSList const *items = selection->itemList();
2392 for (; items != NULL; items = items->next) {
2393 if (SP_IS_STAR((SPItem *) items->data)) {
2394 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2395 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
2396 sp_repr_set_svg_double(repr, "sodipodi:arg2",
2397 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
2398 + M_PI / (gint)adj->value));
2399 SP_OBJECT((SPItem *) items->data)->updateRepr();
2400 modmade = true;
2401 }
2402 }
2403 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2404 _("Star: Change number of corners"));
2406 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2407 }
2409 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
2410 {
2411 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2413 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2414 if (!IS_NAN(adj->value)) {
2415 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2416 prefs->setDouble("/tools/shapes/star/proportion", adj->value);
2417 }
2418 }
2420 // quit if run by the attr_changed listener
2421 if (g_object_get_data( dataKludge, "freeze" )) {
2422 return;
2423 }
2425 // in turn, prevent listener from responding
2426 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2428 bool modmade = false;
2429 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2430 GSList const *items = selection->itemList();
2431 for (; items != NULL; items = items->next) {
2432 if (SP_IS_STAR((SPItem *) items->data)) {
2433 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2435 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
2436 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
2437 if (r2 < r1) {
2438 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
2439 } else {
2440 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
2441 }
2443 SP_OBJECT((SPItem *) items->data)->updateRepr();
2444 modmade = true;
2445 }
2446 }
2448 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2449 _("Star: Change spoke ratio"));
2451 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2452 }
2454 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
2455 {
2456 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2457 bool flat = ege_select_one_action_get_active( act ) == 0;
2459 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2460 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2461 prefs->setBool( "/tools/shapes/star/isflatsided", flat);
2462 }
2464 // quit if run by the attr_changed listener
2465 if (g_object_get_data( dataKludge, "freeze" )) {
2466 return;
2467 }
2469 // in turn, prevent listener from responding
2470 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2472 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2473 GSList const *items = selection->itemList();
2474 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
2475 bool modmade = false;
2477 if ( prop_action ) {
2478 gtk_action_set_sensitive( prop_action, !flat );
2479 }
2481 for (; items != NULL; items = items->next) {
2482 if (SP_IS_STAR((SPItem *) items->data)) {
2483 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2484 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
2485 SP_OBJECT((SPItem *) items->data)->updateRepr();
2486 modmade = true;
2487 }
2488 }
2490 if (modmade) {
2491 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2492 flat ? _("Make polygon") : _("Make star"));
2493 }
2495 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2496 }
2498 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
2499 {
2500 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2502 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2503 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2504 prefs->setDouble("/tools/shapes/star/rounded", (gdouble) adj->value);
2505 }
2507 // quit if run by the attr_changed listener
2508 if (g_object_get_data( dataKludge, "freeze" )) {
2509 return;
2510 }
2512 // in turn, prevent listener from responding
2513 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2515 bool modmade = false;
2517 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2518 GSList const *items = selection->itemList();
2519 for (; items != NULL; items = items->next) {
2520 if (SP_IS_STAR((SPItem *) items->data)) {
2521 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2522 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
2523 SP_OBJECT(items->data)->updateRepr();
2524 modmade = true;
2525 }
2526 }
2527 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2528 _("Star: Change rounding"));
2530 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2531 }
2533 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
2534 {
2535 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2537 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2538 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2539 prefs->setDouble("/tools/shapes/star/randomized", (gdouble) adj->value);
2540 }
2542 // quit if run by the attr_changed listener
2543 if (g_object_get_data( dataKludge, "freeze" )) {
2544 return;
2545 }
2547 // in turn, prevent listener from responding
2548 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
2550 bool modmade = false;
2552 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2553 GSList const *items = selection->itemList();
2554 for (; items != NULL; items = items->next) {
2555 if (SP_IS_STAR((SPItem *) items->data)) {
2556 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2557 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
2558 SP_OBJECT(items->data)->updateRepr();
2559 modmade = true;
2560 }
2561 }
2562 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
2563 _("Star: Change randomization"));
2565 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
2566 }
2569 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2570 gchar const */*old_value*/, gchar const */*new_value*/,
2571 bool /*is_interactive*/, gpointer data)
2572 {
2573 GtkWidget *tbl = GTK_WIDGET(data);
2575 // quit if run by the _changed callbacks
2576 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2577 return;
2578 }
2580 // in turn, prevent callbacks from responding
2581 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2583 GtkAdjustment *adj = 0;
2585 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2586 bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true);
2588 if (!strcmp(name, "inkscape:randomized")) {
2589 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
2590 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
2591 } else if (!strcmp(name, "inkscape:rounded")) {
2592 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
2593 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
2594 } else if (!strcmp(name, "inkscape:flatsided")) {
2595 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
2596 char const *flatsides = repr->attribute("inkscape:flatsided");
2597 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
2598 if ( flatsides && !strcmp(flatsides,"false") ) {
2599 ege_select_one_action_set_active( flat_action, 1 );
2600 gtk_action_set_sensitive( prop_action, TRUE );
2601 } else {
2602 ege_select_one_action_set_active( flat_action, 0 );
2603 gtk_action_set_sensitive( prop_action, FALSE );
2604 }
2605 } else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) {
2606 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
2607 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
2608 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
2609 if (r2 < r1) {
2610 gtk_adjustment_set_value(adj, r2/r1);
2611 } else {
2612 gtk_adjustment_set_value(adj, r1/r2);
2613 }
2614 } else if (!strcmp(name, "sodipodi:sides")) {
2615 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
2616 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
2617 }
2619 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2620 }
2623 static Inkscape::XML::NodeEventVector star_tb_repr_events =
2624 {
2625 NULL, /* child_added */
2626 NULL, /* child_removed */
2627 star_tb_event_attr_changed,
2628 NULL, /* content_changed */
2629 NULL /* order_changed */
2630 };
2633 /**
2634 * \param selection Should not be NULL.
2635 */
2636 static void
2637 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2638 {
2639 int n_selected = 0;
2640 Inkscape::XML::Node *repr = NULL;
2642 purge_repr_listener( tbl, tbl );
2644 for (GSList const *items = selection->itemList();
2645 items != NULL;
2646 items = items->next)
2647 {
2648 if (SP_IS_STAR((SPItem *) items->data)) {
2649 n_selected++;
2650 repr = SP_OBJECT_REPR((SPItem *) items->data);
2651 }
2652 }
2654 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2656 if (n_selected == 0) {
2657 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2658 } else if (n_selected == 1) {
2659 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2661 if (repr) {
2662 g_object_set_data( tbl, "repr", repr );
2663 Inkscape::GC::anchor(repr);
2664 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
2665 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
2666 }
2667 } else {
2668 // FIXME: implement averaging of all parameters for multiple selected stars
2669 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2670 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
2671 }
2672 }
2675 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
2676 {
2677 // FIXME: in this and all other _default functions, set some flag telling the value_changed
2678 // callbacks to lump all the changes for all selected objects in one undo step
2680 GtkAdjustment *adj = 0;
2682 // fixme: make settable in prefs!
2683 gint mag = 5;
2684 gdouble prop = 0.5;
2685 gboolean flat = FALSE;
2686 gdouble randomized = 0;
2687 gdouble rounded = 0;
2689 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
2690 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
2692 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
2693 gtk_action_set_sensitive( sb2, !flat );
2695 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
2696 gtk_adjustment_set_value(adj, mag);
2697 gtk_adjustment_value_changed(adj);
2699 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
2700 gtk_adjustment_set_value(adj, prop);
2701 gtk_adjustment_value_changed(adj);
2703 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
2704 gtk_adjustment_set_value(adj, rounded);
2705 gtk_adjustment_value_changed(adj);
2707 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
2708 gtk_adjustment_set_value(adj, randomized);
2709 gtk_adjustment_value_changed(adj);
2710 }
2713 void
2714 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
2715 {
2716 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
2717 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
2718 GtkWidget *l = gtk_label_new(NULL);
2719 gtk_label_set_markup(GTK_LABEL(l), title);
2720 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
2721 if ( GTK_IS_TOOLBAR(tbl) ) {
2722 gtk_toolbar_append_widget( GTK_TOOLBAR(tbl), boxl, "", "" );
2723 } else {
2724 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
2725 }
2726 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
2727 }
2730 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2731 {
2732 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
2734 {
2735 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
2736 ege_output_action_set_use_markup( act, TRUE );
2737 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2738 g_object_set_data( holder, "mode_action", act );
2739 }
2741 {
2742 EgeAdjustmentAction* eact = 0;
2743 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2744 bool isFlatSided = prefs->getBool("/tools/shapes/star/isflatsided", true);
2746 /* Flatsided checkbox */
2747 {
2748 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2750 GtkTreeIter iter;
2751 gtk_list_store_append( model, &iter );
2752 gtk_list_store_set( model, &iter,
2753 0, _("Polygon"),
2754 1, _("Regular polygon (with one handle) instead of a star"),
2755 2, INKSCAPE_ICON_DRAW_POLYGON,
2756 -1 );
2758 gtk_list_store_append( model, &iter );
2759 gtk_list_store_set( model, &iter,
2760 0, _("Star"),
2761 1, _("Star instead of a regular polygon (with one handle)"),
2762 2, INKSCAPE_ICON_DRAW_STAR,
2763 -1 );
2765 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
2766 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2767 g_object_set_data( holder, "flat_action", act );
2769 ege_select_one_action_set_appearance( act, "full" );
2770 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2771 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2772 ege_select_one_action_set_icon_column( act, 2 );
2773 ege_select_one_action_set_icon_size( act, secondarySize );
2774 ege_select_one_action_set_tooltip_column( act, 1 );
2776 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
2777 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
2778 }
2780 /* Magnitude */
2781 {
2782 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
2783 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
2784 eact = create_adjustment_action( "MagnitudeAction",
2785 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
2786 "/tools/shapes/star/magnitude", 3,
2787 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2788 3, 1024, 1, 5,
2789 labels, values, G_N_ELEMENTS(labels),
2790 sp_stb_magnitude_value_changed,
2791 1.0, 0 );
2792 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2793 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2794 }
2796 /* Spoke ratio */
2797 {
2798 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
2799 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
2800 eact = create_adjustment_action( "SpokeAction",
2801 _("Spoke ratio"), _("Spoke ratio:"),
2802 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
2803 // Base radius is the same for the closest handle.
2804 _("Base radius to tip radius ratio"),
2805 "/tools/shapes/star/proportion", 0.5,
2806 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2807 0.01, 1.0, 0.01, 0.1,
2808 labels, values, G_N_ELEMENTS(labels),
2809 sp_stb_proportion_value_changed );
2810 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2811 g_object_set_data( holder, "prop_action", eact );
2812 }
2814 if ( !isFlatSided ) {
2815 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2816 } else {
2817 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2818 }
2820 /* Roundedness */
2821 {
2822 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
2823 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
2824 eact = create_adjustment_action( "RoundednessAction",
2825 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
2826 "/tools/shapes/star/rounded", 0.0,
2827 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2828 -10.0, 10.0, 0.01, 0.1,
2829 labels, values, G_N_ELEMENTS(labels),
2830 sp_stb_rounded_value_changed );
2831 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2832 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2833 }
2835 /* Randomization */
2836 {
2837 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
2838 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
2839 eact = create_adjustment_action( "RandomizationAction",
2840 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
2841 "/tools/shapes/star/randomized", 0.0,
2842 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2843 -10.0, 10.0, 0.001, 0.01,
2844 labels, values, G_N_ELEMENTS(labels),
2845 sp_stb_randomized_value_changed, 0.1, 3 );
2846 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2847 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2848 }
2849 }
2851 {
2852 /* Reset */
2853 {
2854 GtkAction* act = gtk_action_new( "StarResetAction",
2855 _("Defaults"),
2856 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2857 GTK_STOCK_CLEAR );
2858 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
2859 gtk_action_group_add_action( mainActions, act );
2860 gtk_action_set_sensitive( act, TRUE );
2861 }
2862 }
2864 sigc::connection *connection = new sigc::connection(
2865 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
2866 );
2867 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2868 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2869 }
2872 //########################
2873 //## Rect ##
2874 //########################
2876 static void sp_rtb_sensitivize( GObject *tbl )
2877 {
2878 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
2879 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
2880 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
2882 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
2883 gtk_action_set_sensitive( not_rounded, FALSE );
2884 } else {
2885 gtk_action_set_sensitive( not_rounded, TRUE );
2886 }
2887 }
2890 static void
2891 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
2892 void (*setter)(SPRect *, gdouble))
2893 {
2894 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2896 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2897 SPUnit const *unit = tracker->getActiveUnit();
2899 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2900 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
2901 prefs->setDouble(Glib::ustring("/tools/shapes/rect/") + value_name, sp_units_get_pixels(adj->value, *unit));
2902 }
2904 // quit if run by the attr_changed listener
2905 if (g_object_get_data( tbl, "freeze" )) {
2906 return;
2907 }
2909 // in turn, prevent listener from responding
2910 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2912 bool modmade = false;
2913 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2914 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2915 if (SP_IS_RECT(items->data)) {
2916 if (adj->value != 0) {
2917 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2918 } else {
2919 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2920 }
2921 modmade = true;
2922 }
2923 }
2925 sp_rtb_sensitivize( tbl );
2927 if (modmade) {
2928 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2929 _("Change rectangle"));
2930 }
2932 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2933 }
2935 static void
2936 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2937 {
2938 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2939 }
2941 static void
2942 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2943 {
2944 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2945 }
2947 static void
2948 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2949 {
2950 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2951 }
2953 static void
2954 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2955 {
2956 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2957 }
2961 static void
2962 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2963 {
2964 GtkAdjustment *adj = 0;
2966 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2967 gtk_adjustment_set_value(adj, 0.0);
2968 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2969 gtk_adjustment_value_changed(adj);
2971 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2972 gtk_adjustment_set_value(adj, 0.0);
2973 gtk_adjustment_value_changed(adj);
2975 sp_rtb_sensitivize( obj );
2976 }
2978 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2979 gchar const */*old_value*/, gchar const */*new_value*/,
2980 bool /*is_interactive*/, gpointer data)
2981 {
2982 GObject *tbl = G_OBJECT(data);
2984 // quit if run by the _changed callbacks
2985 if (g_object_get_data( tbl, "freeze" )) {
2986 return;
2987 }
2989 // in turn, prevent callbacks from responding
2990 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2992 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2993 SPUnit const *unit = tracker->getActiveUnit();
2995 gpointer item = g_object_get_data( tbl, "item" );
2996 if (item && SP_IS_RECT(item)) {
2997 {
2998 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2999 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
3000 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
3001 }
3003 {
3004 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
3005 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
3006 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
3007 }
3009 {
3010 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
3011 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
3012 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
3013 }
3015 {
3016 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
3017 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
3018 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
3019 }
3020 }
3022 sp_rtb_sensitivize( tbl );
3024 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3025 }
3028 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
3029 NULL, /* child_added */
3030 NULL, /* child_removed */
3031 rect_tb_event_attr_changed,
3032 NULL, /* content_changed */
3033 NULL /* order_changed */
3034 };
3036 /**
3037 * \param selection should not be NULL.
3038 */
3039 static void
3040 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3041 {
3042 int n_selected = 0;
3043 Inkscape::XML::Node *repr = NULL;
3044 SPItem *item = NULL;
3046 if ( g_object_get_data( tbl, "repr" ) ) {
3047 g_object_set_data( tbl, "item", NULL );
3048 }
3049 purge_repr_listener( tbl, tbl );
3051 for (GSList const *items = selection->itemList();
3052 items != NULL;
3053 items = items->next) {
3054 if (SP_IS_RECT((SPItem *) items->data)) {
3055 n_selected++;
3056 item = (SPItem *) items->data;
3057 repr = SP_OBJECT_REPR(item);
3058 }
3059 }
3061 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3063 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3065 if (n_selected == 0) {
3066 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3068 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
3069 gtk_action_set_sensitive(w, FALSE);
3070 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
3071 gtk_action_set_sensitive(h, FALSE);
3073 } else if (n_selected == 1) {
3074 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3075 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3077 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
3078 gtk_action_set_sensitive(w, TRUE);
3079 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
3080 gtk_action_set_sensitive(h, TRUE);
3082 if (repr) {
3083 g_object_set_data( tbl, "repr", repr );
3084 g_object_set_data( tbl, "item", item );
3085 Inkscape::GC::anchor(repr);
3086 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
3087 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
3088 }
3089 } else {
3090 // FIXME: implement averaging of all parameters for multiple selected
3091 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3092 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3093 sp_rtb_sensitivize( tbl );
3094 }
3095 }
3098 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3099 {
3100 EgeAdjustmentAction* eact = 0;
3101 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
3103 {
3104 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
3105 ege_output_action_set_use_markup( act, TRUE );
3106 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3107 g_object_set_data( holder, "mode_action", act );
3108 }
3110 // rx/ry units menu: create
3111 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
3112 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
3113 // fixme: add % meaning per cent of the width/height
3114 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
3115 g_object_set_data( holder, "tracker", tracker );
3117 /* W */
3118 {
3119 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
3120 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
3121 eact = create_adjustment_action( "RectWidthAction",
3122 _("Width"), _("W:"), _("Width of rectangle"),
3123 "/tools/shapes/rect/width", 0,
3124 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
3125 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3126 labels, values, G_N_ELEMENTS(labels),
3127 sp_rtb_width_value_changed );
3128 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3129 g_object_set_data( holder, "width_action", eact );
3130 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3131 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3132 }
3134 /* H */
3135 {
3136 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
3137 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
3138 eact = create_adjustment_action( "RectHeightAction",
3139 _("Height"), _("H:"), _("Height of rectangle"),
3140 "/tools/shapes/rect/height", 0,
3141 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3142 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3143 labels, values, G_N_ELEMENTS(labels),
3144 sp_rtb_height_value_changed );
3145 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3146 g_object_set_data( holder, "height_action", eact );
3147 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3148 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3149 }
3151 /* rx */
3152 {
3153 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
3154 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
3155 eact = create_adjustment_action( "RadiusXAction",
3156 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
3157 "/tools/shapes/rect/rx", 0,
3158 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3159 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3160 labels, values, G_N_ELEMENTS(labels),
3161 sp_rtb_rx_value_changed);
3162 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3163 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3164 }
3166 /* ry */
3167 {
3168 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
3169 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
3170 eact = create_adjustment_action( "RadiusYAction",
3171 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
3172 "/tools/shapes/rect/ry", 0,
3173 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3174 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
3175 labels, values, G_N_ELEMENTS(labels),
3176 sp_rtb_ry_value_changed);
3177 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
3178 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3179 }
3181 // add the units menu
3182 {
3183 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
3184 gtk_action_group_add_action( mainActions, act );
3185 }
3187 /* Reset */
3188 {
3189 InkAction* inky = ink_action_new( "RectResetAction",
3190 _("Not rounded"),
3191 _("Make corners sharp"),
3192 INKSCAPE_ICON_RECTANGLE_MAKE_CORNERS_SHARP,
3193 secondarySize );
3194 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
3195 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3196 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3197 g_object_set_data( holder, "not_rounded", inky );
3198 }
3200 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
3201 sp_rtb_sensitivize( holder );
3203 sigc::connection *connection = new sigc::connection(
3204 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
3205 );
3206 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3207 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3208 }
3210 //########################
3211 //## 3D Box ##
3212 //########################
3214 // normalize angle so that it lies in the interval [0,360]
3215 static double box3d_normalize_angle (double a) {
3216 double angle = a + ((int) (a/360.0))*360;
3217 if (angle < 0) {
3218 angle += 360.0;
3219 }
3220 return angle;
3221 }
3223 static void
3224 box3d_set_button_and_adjustment(Persp3D *persp, Proj::Axis axis,
3225 GtkAdjustment *adj, GtkAction *act, GtkToggleAction *tact) {
3226 // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
3227 // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
3228 // are reset).
3229 bool is_infinite = !persp3d_VP_is_finite(persp->perspective_impl, axis);
3231 if (is_infinite) {
3232 gtk_toggle_action_set_active(tact, TRUE);
3233 gtk_action_set_sensitive(act, TRUE);
3235 double angle = persp3d_get_infinite_angle(persp, axis);
3236 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
3237 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
3238 }
3239 } else {
3240 gtk_toggle_action_set_active(tact, FALSE);
3241 gtk_action_set_sensitive(act, FALSE);
3242 }
3243 }
3245 static void
3246 box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) {
3247 if (!persp_repr) {
3248 g_print ("No perspective given to box3d_resync_toolbar().\n");
3249 return;
3250 }
3252 GtkWidget *tbl = GTK_WIDGET(data);
3253 GtkAdjustment *adj = 0;
3254 GtkAction *act = 0;
3255 GtkToggleAction *tact = 0;
3256 Persp3D *persp = persp3d_get_from_repr(persp_repr);
3257 if (!persp) {
3258 // Hmm, is it an error if this happens?
3259 return;
3260 }
3261 {
3262 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
3263 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
3264 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action;
3266 box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact);
3267 }
3268 {
3269 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_y"));
3270 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action"));
3271 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action;
3273 box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact);
3274 }
3275 {
3276 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_z"));
3277 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action"));
3278 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action;
3280 box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact);
3281 }
3282 }
3284 static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3285 gchar const */*old_value*/, gchar const */*new_value*/,
3286 bool /*is_interactive*/, gpointer data)
3287 {
3288 GtkWidget *tbl = GTK_WIDGET(data);
3290 // quit if run by the attr_changed or selection changed listener
3291 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3292 return;
3293 }
3295 // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling
3296 // sp_document_maybe_done() when the document is undo insensitive)
3297 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3299 // TODO: Only update the appropriate part of the toolbar
3300 // if (!strcmp(name, "inkscape:vp_z")) {
3301 box3d_resync_toolbar(repr, G_OBJECT(tbl));
3302 // }
3304 Persp3D *persp = persp3d_get_from_repr(repr);
3305 persp3d_update_box_reprs(persp);
3307 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3308 }
3310 static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
3311 {
3312 NULL, /* child_added */
3313 NULL, /* child_removed */
3314 box3d_persp_tb_event_attr_changed,
3315 NULL, /* content_changed */
3316 NULL /* order_changed */
3317 };
3319 /**
3320 * \param selection Should not be NULL.
3321 */
3322 // FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
3323 // Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
3324 static void
3325 box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3326 {
3327 // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
3328 // disable the angle entry fields for this direction (otherwise entering a value in them should only
3329 // update the perspectives with infinite VPs and leave the other ones untouched).
3331 Inkscape::XML::Node *persp_repr = NULL;
3332 purge_repr_listener(tbl, tbl);
3334 SPItem *item = selection->singleItem();
3335 if (item && SP_IS_BOX3D(item)) {
3336 // FIXME: Also deal with multiple selected boxes
3337 SPBox3D *box = SP_BOX3D(item);
3338 Persp3D *persp = box3d_get_perspective(box);
3339 persp_repr = SP_OBJECT_REPR(persp);
3340 if (persp_repr) {
3341 g_object_set_data(tbl, "repr", persp_repr);
3342 Inkscape::GC::anchor(persp_repr);
3343 sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl);
3344 sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
3345 }
3347 inkscape_active_document()->setCurrentPersp3D(persp3d_get_from_repr(persp_repr));
3348 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3349 prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id"));
3351 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
3352 box3d_resync_toolbar(persp_repr, tbl);
3353 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE));
3354 }
3355 }
3357 static void
3358 box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis)
3359 {
3360 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
3361 SPDocument *document = sp_desktop_document(desktop);
3363 // quit if run by the attr_changed or selection changed listener
3364 if (g_object_get_data( dataKludge, "freeze" )) {
3365 return;
3366 }
3368 // in turn, prevent listener from responding
3369 g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE));
3371 std::list<Persp3D *> sel_persps = sp_desktop_selection(desktop)->perspList();
3372 if (sel_persps.empty()) {
3373 // this can happen when the document is created; we silently ignore it
3374 return;
3375 }
3376 Persp3D *persp = sel_persps.front();
3378 persp->perspective_impl->tmat.set_infinite_direction (axis, adj->value);
3379 SP_OBJECT(persp)->updateRepr();
3381 // TODO: use the correct axis here, too
3382 sp_document_maybe_done(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)"));
3384 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
3385 }
3388 static void
3389 box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge)
3390 {
3391 box3d_angle_value_changed(adj, dataKludge, Proj::X);
3392 }
3394 static void
3395 box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge)
3396 {
3397 box3d_angle_value_changed(adj, dataKludge, Proj::Y);
3398 }
3400 static void
3401 box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge)
3402 {
3403 box3d_angle_value_changed(adj, dataKludge, Proj::Z);
3404 }
3407 static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction */*box3d_angle*/, Proj::Axis axis )
3408 {
3409 // TODO: Take all selected perspectives into account
3410 std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList();
3411 if (sel_persps.empty()) {
3412 // this can happen when the document is created; we silently ignore it
3413 return;
3414 }
3415 Persp3D *persp = sel_persps.front();
3417 bool set_infinite = gtk_toggle_action_get_active(act);
3418 persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
3419 }
3421 static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
3422 {
3423 box3d_vp_state_changed(act, box3d_angle, Proj::X);
3424 }
3426 static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
3427 {
3428 box3d_vp_state_changed(act, box3d_angle, Proj::Y);
3429 }
3431 static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
3432 {
3433 box3d_vp_state_changed(act, box3d_angle, Proj::Z);
3434 }
3436 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3437 {
3438 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3439 EgeAdjustmentAction* eact = 0;
3440 SPDocument *document = sp_desktop_document (desktop);
3441 Persp3DImpl *persp_impl = document->getCurrentPersp3DImpl();
3443 EgeAdjustmentAction* box3d_angle_x = 0;
3444 EgeAdjustmentAction* box3d_angle_y = 0;
3445 EgeAdjustmentAction* box3d_angle_z = 0;
3447 /* Angle X */
3448 {
3449 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
3450 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3451 eact = create_adjustment_action( "3DBoxAngleXAction",
3452 _("Angle in X direction"), _("Angle X:"),
3453 // Translators: PL is short for 'perspective line'
3454 _("Angle of PLs in X direction"),
3455 "/tools/shapes/3dbox/box3d_angle_x", 30,
3456 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
3457 -360.0, 360.0, 1.0, 10.0,
3458 labels, values, G_N_ELEMENTS(labels),
3459 box3d_angle_x_value_changed );
3460 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3461 g_object_set_data( holder, "box3d_angle_x_action", eact );
3462 box3d_angle_x = eact;
3463 }
3465 if (!persp3d_VP_is_finite(persp_impl, Proj::X)) {
3466 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3467 } else {
3468 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3469 }
3472 /* VP X state */
3473 {
3474 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction",
3475 // Translators: VP is short for 'vanishing point'
3476 _("State of VP in X direction"),
3477 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
3478 INKSCAPE_ICON_PERSPECTIVE_PARALLEL,
3479 Inkscape::ICON_SIZE_DECORATION );
3480 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3481 g_object_set_data( holder, "box3d_vp_x_state_action", act );
3482 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x );
3483 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) );
3484 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) );
3485 }
3487 /* Angle Y */
3488 {
3489 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
3490 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3491 eact = create_adjustment_action( "3DBoxAngleYAction",
3492 _("Angle in Y direction"), _("Angle Y:"),
3493 // Translators: PL is short for 'perspective line'
3494 _("Angle of PLs in Y direction"),
3495 "/tools/shapes/3dbox/box3d_angle_y", 30,
3496 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3497 -360.0, 360.0, 1.0, 10.0,
3498 labels, values, G_N_ELEMENTS(labels),
3499 box3d_angle_y_value_changed );
3500 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3501 g_object_set_data( holder, "box3d_angle_y_action", eact );
3502 box3d_angle_y = eact;
3503 }
3505 if (!persp3d_VP_is_finite(persp_impl, Proj::Y)) {
3506 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3507 } else {
3508 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3509 }
3511 /* VP Y state */
3512 {
3513 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction",
3514 // Translators: VP is short for 'vanishing point'
3515 _("State of VP in Y direction"),
3516 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
3517 INKSCAPE_ICON_PERSPECTIVE_PARALLEL,
3518 Inkscape::ICON_SIZE_DECORATION );
3519 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3520 g_object_set_data( holder, "box3d_vp_y_state_action", act );
3521 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y );
3522 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) );
3523 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) );
3524 }
3526 /* Angle Z */
3527 {
3528 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
3529 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3530 eact = create_adjustment_action( "3DBoxAngleZAction",
3531 _("Angle in Z direction"), _("Angle Z:"),
3532 // Translators: PL is short for 'perspective line'
3533 _("Angle of PLs in Z direction"),
3534 "/tools/shapes/3dbox/box3d_angle_z", 30,
3535 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3536 -360.0, 360.0, 1.0, 10.0,
3537 labels, values, G_N_ELEMENTS(labels),
3538 box3d_angle_z_value_changed );
3539 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3540 g_object_set_data( holder, "box3d_angle_z_action", eact );
3541 box3d_angle_z = eact;
3542 }
3544 if (!persp3d_VP_is_finite(persp_impl, Proj::Z)) {
3545 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3546 } else {
3547 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
3548 }
3550 /* VP Z state */
3551 {
3552 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction",
3553 // Translators: VP is short for 'vanishing point'
3554 _("State of VP in Z direction"),
3555 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
3556 INKSCAPE_ICON_PERSPECTIVE_PARALLEL,
3557 Inkscape::ICON_SIZE_DECORATION );
3558 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3559 g_object_set_data( holder, "box3d_vp_z_state_action", act );
3560 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z );
3561 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) );
3562 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) );
3563 }
3565 sigc::connection *connection = new sigc::connection(
3566 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
3567 );
3568 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
3569 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
3570 }
3572 //########################
3573 //## Spiral ##
3574 //########################
3576 static void
3577 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustring const &value_name)
3578 {
3579 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3581 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3582 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3583 prefs->setDouble("/tools/shapes/spiral/" + value_name, adj->value);
3584 }
3586 // quit if run by the attr_changed listener
3587 if (g_object_get_data( tbl, "freeze" )) {
3588 return;
3589 }
3591 // in turn, prevent listener from responding
3592 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3594 gchar* namespaced_name = g_strconcat("sodipodi:", value_name.data(), NULL);
3596 bool modmade = false;
3597 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3598 items != NULL;
3599 items = items->next)
3600 {
3601 if (SP_IS_SPIRAL((SPItem *) items->data)) {
3602 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3603 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
3604 SP_OBJECT((SPItem *) items->data)->updateRepr();
3605 modmade = true;
3606 }
3607 }
3609 g_free(namespaced_name);
3611 if (modmade) {
3612 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
3613 _("Change spiral"));
3614 }
3616 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3617 }
3619 static void
3620 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
3621 {
3622 sp_spl_tb_value_changed(adj, tbl, "revolution");
3623 }
3625 static void
3626 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
3627 {
3628 sp_spl_tb_value_changed(adj, tbl, "expansion");
3629 }
3631 static void
3632 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
3633 {
3634 sp_spl_tb_value_changed(adj, tbl, "t0");
3635 }
3637 static void
3638 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
3639 {
3640 GtkWidget *tbl = GTK_WIDGET(obj);
3642 GtkAdjustment *adj;
3644 // fixme: make settable
3645 gdouble rev = 5;
3646 gdouble exp = 1.0;
3647 gdouble t0 = 0.0;
3649 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
3650 gtk_adjustment_set_value(adj, rev);
3651 gtk_adjustment_value_changed(adj);
3653 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
3654 gtk_adjustment_set_value(adj, exp);
3655 gtk_adjustment_value_changed(adj);
3657 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
3658 gtk_adjustment_set_value(adj, t0);
3659 gtk_adjustment_value_changed(adj);
3661 spinbutton_defocus(GTK_OBJECT(tbl));
3662 }
3665 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3666 gchar const */*old_value*/, gchar const */*new_value*/,
3667 bool /*is_interactive*/, gpointer data)
3668 {
3669 GtkWidget *tbl = GTK_WIDGET(data);
3671 // quit if run by the _changed callbacks
3672 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
3673 return;
3674 }
3676 // in turn, prevent callbacks from responding
3677 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
3679 GtkAdjustment *adj;
3680 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
3681 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
3683 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
3684 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
3686 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
3687 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
3689 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
3690 }
3693 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
3694 NULL, /* child_added */
3695 NULL, /* child_removed */
3696 spiral_tb_event_attr_changed,
3697 NULL, /* content_changed */
3698 NULL /* order_changed */
3699 };
3701 static void
3702 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3703 {
3704 int n_selected = 0;
3705 Inkscape::XML::Node *repr = NULL;
3707 purge_repr_listener( tbl, tbl );
3709 for (GSList const *items = selection->itemList();
3710 items != NULL;
3711 items = items->next)
3712 {
3713 if (SP_IS_SPIRAL((SPItem *) items->data)) {
3714 n_selected++;
3715 repr = SP_OBJECT_REPR((SPItem *) items->data);
3716 }
3717 }
3719 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3721 if (n_selected == 0) {
3722 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3723 } else if (n_selected == 1) {
3724 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3726 if (repr) {
3727 g_object_set_data( tbl, "repr", repr );
3728 Inkscape::GC::anchor(repr);
3729 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
3730 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
3731 }
3732 } else {
3733 // FIXME: implement averaging of all parameters for multiple selected
3734 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3735 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3736 }
3737 }
3740 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3741 {
3742 EgeAdjustmentAction* eact = 0;
3743 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
3745 {
3746 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
3747 ege_output_action_set_use_markup( act, TRUE );
3748 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3749 g_object_set_data( holder, "mode_action", act );
3750 }
3752 /* Revolution */
3753 {
3754 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
3755 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
3756 eact = create_adjustment_action( "SpiralRevolutionAction",
3757 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
3758 "/tools/shapes/spiral/revolution", 3.0,
3759 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
3760 0.01, 1024.0, 0.1, 1.0,
3761 labels, values, G_N_ELEMENTS(labels),
3762 sp_spl_tb_revolution_value_changed, 1, 2);
3763 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3764 }
3766 /* Expansion */
3767 {
3768 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
3769 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
3770 eact = create_adjustment_action( "SpiralExpansionAction",
3771 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
3772 "/tools/shapes/spiral/expansion", 1.0,
3773 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3774 0.0, 1000.0, 0.01, 1.0,
3775 labels, values, G_N_ELEMENTS(labels),
3776 sp_spl_tb_expansion_value_changed);
3777 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3778 }
3780 /* T0 */
3781 {
3782 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
3783 gdouble values[] = {0, 0.5, 0.9};
3784 eact = create_adjustment_action( "SpiralT0Action",
3785 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
3786 "/tools/shapes/spiral/t0", 0.0,
3787 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3788 0.0, 0.999, 0.01, 1.0,
3789 labels, values, G_N_ELEMENTS(labels),
3790 sp_spl_tb_t0_value_changed);
3791 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3792 }
3794 /* Reset */
3795 {
3796 InkAction* inky = ink_action_new( "SpiralResetAction",
3797 _("Defaults"),
3798 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
3799 GTK_STOCK_CLEAR,
3800 secondarySize );
3801 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
3802 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3803 }
3806 sigc::connection *connection = new sigc::connection(
3807 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
3808 );
3809 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3810 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3811 }
3813 //########################
3814 //## Pen/Pencil ##
3815 //########################
3817 /* This is used in generic functions below to share large portions of code between pen and pencil tool */
3818 static Glib::ustring const
3819 freehand_tool_name(GObject *dataKludge)
3820 {
3821 SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
3822 return ( tools_isactive(desktop, TOOLS_FREEHAND_PEN)
3823 ? "/tools/freehand/pen"
3824 : "/tools/freehand/pencil" );
3825 }
3827 static void freehand_mode_changed(EgeSelectOneAction* act, GObject* tbl)
3828 {
3829 gint mode = ege_select_one_action_get_active(act);
3831 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3832 prefs->setInt(freehand_tool_name(tbl) + "/freehand-mode", mode);
3834 SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop");
3836 // in pen tool we have more options than in pencil tool; if one of them was chosen, we do any
3837 // preparatory work here
3838 if (SP_IS_PEN_CONTEXT(desktop->event_context)) {
3839 SPPenContext *pc = SP_PEN_CONTEXT(desktop->event_context);
3840 sp_pen_context_set_polyline_mode(pc);
3841 }
3842 }
3844 static void sp_add_freehand_mode_toggle(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil)
3845 {
3846 /* Freehand mode toggle buttons */
3847 {
3848 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3849 guint freehandMode = prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/freehand-mode" : "/tools/freehand/pen/freehand-mode" ), 0);
3850 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
3852 {
3853 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3855 GtkTreeIter iter;
3856 gtk_list_store_append( model, &iter );
3857 gtk_list_store_set( model, &iter,
3858 0, _("Bezier"),
3859 1, _("Create regular Bezier path"),
3860 2, INKSCAPE_ICON_PATH_MODE_BEZIER,
3861 -1 );
3863 gtk_list_store_append( model, &iter );
3864 gtk_list_store_set( model, &iter,
3865 0, _("Spiro"),
3866 1, _("Create Spiro path"),
3867 2, INKSCAPE_ICON_PATH_MODE_SPIRO,
3868 -1 );
3870 if (!tool_is_pencil) {
3871 gtk_list_store_append( model, &iter );
3872 gtk_list_store_set( model, &iter,
3873 0, _("Zigzag"),
3874 1, _("Create a sequence of straight line segments"),
3875 2, INKSCAPE_ICON_PATH_MODE_POLYLINE,
3876 -1 );
3878 gtk_list_store_append( model, &iter );
3879 gtk_list_store_set( model, &iter,
3880 0, _("Paraxial"),
3881 1, _("Create a sequence of paraxial line segments"),
3882 2, INKSCAPE_ICON_PATH_MODE_POLYLINE_PARAXIAL,
3883 -1 );
3884 }
3886 EgeSelectOneAction* act = ege_select_one_action_new(tool_is_pencil ?
3887 "FreehandModeActionPencil" :
3888 "FreehandModeActionPen",
3889 (_("Mode:")), (_("Mode of new lines drawn by this tool")), NULL, GTK_TREE_MODEL(model) );
3890 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3892 ege_select_one_action_set_appearance( act, "full" );
3893 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3894 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3895 ege_select_one_action_set_icon_column( act, 2 );
3896 ege_select_one_action_set_icon_size( act, secondarySize );
3897 ege_select_one_action_set_tooltip_column( act, 1 );
3899 ege_select_one_action_set_active( act, freehandMode);
3900 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(freehand_mode_changed), holder);
3901 }
3902 }
3903 }
3905 static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge) {
3906 gint shape = ege_select_one_action_get_active( act );
3907 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3908 prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape);
3909 }
3911 /**
3912 * \brief Generate the list of freehand advanced shape option entries.
3913 */
3914 GList * freehand_shape_dropdown_items_list() {
3915 GList *glist = NULL;
3917 glist = g_list_append (glist, _("None"));
3918 glist = g_list_append (glist, _("Triangle in"));
3919 glist = g_list_append (glist, _("Triangle out"));
3920 glist = g_list_append (glist, _("Ellipse"));
3921 glist = g_list_append (glist, _("From clipboard"));
3923 return glist;
3924 }
3926 static void
3927 freehand_add_advanced_shape_options(GtkActionGroup* mainActions, GObject* holder, bool tool_is_pencil) {
3928 /*advanced shape options */
3929 {
3930 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3931 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
3933 GList* items = 0;
3934 gint count = 0;
3935 for ( items = freehand_shape_dropdown_items_list(); items ; items = g_list_next(items) )
3936 {
3937 GtkTreeIter iter;
3938 gtk_list_store_append( model, &iter );
3939 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
3940 count++;
3941 }
3942 g_list_free( items );
3943 items = 0;
3944 EgeSelectOneAction* act1 = ege_select_one_action_new(
3945 tool_is_pencil ? "SetPencilShapeAction" : "SetPenShapeAction",
3946 _("Shape:"), (_("Shape of new paths drawn by this tool")), NULL, GTK_TREE_MODEL(model));
3947 g_object_set( act1, "short_label", _("Shape:"), NULL );
3948 ege_select_one_action_set_appearance( act1, "compact" );
3949 ege_select_one_action_set_active( act1, prefs->getInt(( tool_is_pencil ? "/tools/freehand/pencil/shape" : "/tools/freehand/pen/shape" ), 0) );
3950 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(freehand_change_shape), holder );
3951 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
3952 g_object_set_data( holder, "shape_action", act1 );
3953 }
3954 }
3956 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3957 {
3958 sp_add_freehand_mode_toggle(mainActions, holder, false);
3959 freehand_add_advanced_shape_options(mainActions, holder, false);
3960 }
3963 static void
3964 sp_pencil_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
3965 {
3966 GtkWidget *tbl = GTK_WIDGET(obj);
3968 GtkAdjustment *adj;
3970 // fixme: make settable
3971 gdouble tolerance = 4;
3973 adj = (GtkAdjustment*)gtk_object_get_data(obj, "tolerance");
3974 gtk_adjustment_set_value(adj, tolerance);
3975 gtk_adjustment_value_changed(adj);
3977 spinbutton_defocus(GTK_OBJECT(tbl));
3978 }
3980 static void
3981 sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl)
3982 {
3983 // quit if run by the attr_changed listener
3984 if (g_object_get_data( tbl, "freeze" )) {
3985 return;
3986 }
3987 // in turn, prevent listener from responding
3988 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
3989 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3990 prefs->setDouble("/tools/freehand/pencil/tolerance", adj->value);
3991 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3992 }
3994 /*
3995 class PencilToleranceObserver : public Inkscape::Preferences::Observer {
3996 public:
3997 PencilToleranceObserver(Glib::ustring const &path, GObject *x) : Observer(path), _obj(x)
3998 {
3999 g_object_set_data(_obj, "prefobserver", this);
4000 }
4001 virtual ~PencilToleranceObserver() {
4002 if (g_object_get_data(_obj, "prefobserver") == this) {
4003 g_object_set_data(_obj, "prefobserver", NULL);
4004 }
4005 }
4006 virtual void notify(Inkscape::Preferences::Entry const &val) {
4007 GObject* tbl = _obj;
4008 if (g_object_get_data( tbl, "freeze" )) {
4009 return;
4010 }
4011 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4013 GtkAdjustment * adj = (GtkAdjustment*)g_object_get_data(tbl, "tolerance");
4015 double v = val.getDouble(adj->value);
4016 gtk_adjustment_set_value(adj, v);
4017 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4018 }
4019 private:
4020 GObject *_obj;
4021 };
4022 */
4024 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4025 {
4026 sp_add_freehand_mode_toggle(mainActions, holder, true);
4028 EgeAdjustmentAction* eact = 0;
4030 /* Tolerance */
4031 {
4032 gchar const* labels[] = {_("(many nodes, rough)"), _("(default)"), 0, 0, 0, 0, _("(few nodes, smooth)")};
4033 gdouble values[] = {1, 10, 20, 30, 50, 75, 100};
4034 eact = create_adjustment_action( "PencilToleranceAction",
4035 _("Smoothing:"), _("Smoothing: "),
4036 _("How much smoothing (simplifying) is applied to the line"),
4037 "/tools/freehand/pencil/tolerance",
4038 3.0,
4039 GTK_WIDGET(desktop->canvas), NULL,
4040 holder, TRUE, "altx-pencil",
4041 1, 100.0, 0.5, 1.0,
4042 labels, values, G_N_ELEMENTS(labels),
4043 sp_pencil_tb_tolerance_value_changed,
4044 1, 2);
4045 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4046 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4047 }
4049 /* advanced shape options */
4050 freehand_add_advanced_shape_options(mainActions, holder, true);
4052 /* Reset */
4053 {
4054 InkAction* inky = ink_action_new( "PencilResetAction",
4055 _("Defaults"),
4056 _("Reset pencil parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
4057 GTK_STOCK_CLEAR,
4058 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4059 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder );
4060 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4061 }
4063 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
4065 }
4068 //########################
4069 //## Tweak ##
4070 //########################
4072 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
4073 {
4074 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4075 prefs->setDouble( "/tools/tweak/width", adj->value * 0.01 );
4076 }
4078 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
4079 {
4080 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4081 prefs->setDouble( "/tools/tweak/force", adj->value * 0.01 );
4082 }
4084 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
4085 {
4086 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4087 prefs->setBool("/tools/tweak/usepressure", gtk_toggle_action_get_active(act));
4088 }
4090 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
4091 {
4092 int mode = ege_select_one_action_get_active( act );
4093 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4094 prefs->setInt("/tools/tweak/mode", mode);
4096 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
4097 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
4098 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
4099 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
4100 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
4101 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
4102 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
4103 if (doh) gtk_action_set_sensitive (doh, TRUE);
4104 if (dos) gtk_action_set_sensitive (dos, TRUE);
4105 if (dol) gtk_action_set_sensitive (dol, TRUE);
4106 if (doo) gtk_action_set_sensitive (doo, TRUE);
4107 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
4108 if (fid) gtk_action_set_sensitive (fid, FALSE);
4109 } else {
4110 if (doh) gtk_action_set_sensitive (doh, FALSE);
4111 if (dos) gtk_action_set_sensitive (dos, FALSE);
4112 if (dol) gtk_action_set_sensitive (dol, FALSE);
4113 if (doo) gtk_action_set_sensitive (doo, FALSE);
4114 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
4115 if (fid) gtk_action_set_sensitive (fid, TRUE);
4116 }
4117 }
4119 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
4120 {
4121 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4122 prefs->setDouble( "/tools/tweak/fidelity", adj->value * 0.01 );
4123 }
4125 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
4126 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4127 prefs->setBool("/tools/tweak/doh", gtk_toggle_action_get_active(act));
4128 }
4129 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
4130 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4131 prefs->setBool("/tools/tweak/dos", gtk_toggle_action_get_active(act));
4132 }
4133 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
4134 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4135 prefs->setBool("/tools/tweak/dol", gtk_toggle_action_get_active(act));
4136 }
4137 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
4138 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4139 prefs->setBool("/tools/tweak/doo", gtk_toggle_action_get_active(act));
4140 }
4142 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4143 {
4144 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
4145 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4147 {
4148 /* Width */
4149 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
4150 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
4151 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
4152 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
4153 "/tools/tweak/width", 15,
4154 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
4155 1, 100, 1.0, 10.0,
4156 labels, values, G_N_ELEMENTS(labels),
4157 sp_tweak_width_value_changed, 0.01, 0, 100 );
4158 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4159 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4160 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4161 }
4164 {
4165 /* Force */
4166 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
4167 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
4168 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
4169 _("Force"), _("Force:"), _("The force of the tweak action"),
4170 "/tools/tweak/force", 20,
4171 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
4172 1, 100, 1.0, 10.0,
4173 labels, values, G_N_ELEMENTS(labels),
4174 sp_tweak_force_value_changed, 0.01, 0, 100 );
4175 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4176 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4177 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4178 }
4180 /* Mode */
4181 {
4182 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
4184 GtkTreeIter iter;
4185 gtk_list_store_append( model, &iter );
4186 gtk_list_store_set( model, &iter,
4187 0, _("Move mode"),
4188 1, _("Move objects in any direction"),
4189 2, INKSCAPE_ICON_OBJECT_TWEAK_PUSH,
4190 -1 );
4192 gtk_list_store_append( model, &iter );
4193 gtk_list_store_set( model, &iter,
4194 0, _("Move in/out mode"),
4195 1, _("Move objects towards cursor; with Shift from cursor"),
4196 2, INKSCAPE_ICON_OBJECT_TWEAK_ATTRACT,
4197 -1 );
4199 gtk_list_store_append( model, &iter );
4200 gtk_list_store_set( model, &iter,
4201 0, _("Move jitter mode"),
4202 1, _("Move objects in random directions"),
4203 2, INKSCAPE_ICON_OBJECT_TWEAK_RANDOMIZE,
4204 -1 );
4206 gtk_list_store_append( model, &iter );
4207 gtk_list_store_set( model, &iter,
4208 0, _("Scale mode"),
4209 1, _("Shrink objects, with Shift enlarge"),
4210 2, INKSCAPE_ICON_OBJECT_TWEAK_SHRINK,
4211 -1 );
4213 gtk_list_store_append( model, &iter );
4214 gtk_list_store_set( model, &iter,
4215 0, _("Rotate mode"),
4216 1, _("Rotate objects, with Shift counterclockwise"),
4217 2, INKSCAPE_ICON_OBJECT_TWEAK_ROTATE,
4218 -1 );
4220 gtk_list_store_append( model, &iter );
4221 gtk_list_store_set( model, &iter,
4222 0, _("Duplicate/delete mode"),
4223 1, _("Duplicate objects, with Shift delete"),
4224 2, INKSCAPE_ICON_OBJECT_TWEAK_DUPLICATE,
4225 -1 );
4227 gtk_list_store_append( model, &iter );
4228 gtk_list_store_set( model, &iter,
4229 0, _("Push mode"),
4230 1, _("Push parts of paths in any direction"),
4231 2, INKSCAPE_ICON_PATH_TWEAK_PUSH,
4232 -1 );
4234 gtk_list_store_append( model, &iter );
4235 gtk_list_store_set( model, &iter,
4236 0, _("Shrink/grow mode"),
4237 1, _("Shrink (inset) parts of paths; with Shift grow (outset)"),
4238 2, INKSCAPE_ICON_PATH_TWEAK_SHRINK,
4239 -1 );
4241 gtk_list_store_append( model, &iter );
4242 gtk_list_store_set( model, &iter,
4243 0, _("Attract/repel mode"),
4244 1, _("Attract parts of paths towards cursor; with Shift from cursor"),
4245 2, INKSCAPE_ICON_PATH_TWEAK_ATTRACT,
4246 -1 );
4248 gtk_list_store_append( model, &iter );
4249 gtk_list_store_set( model, &iter,
4250 0, _("Roughen mode"),
4251 1, _("Roughen parts of paths"),
4252 2, INKSCAPE_ICON_PATH_TWEAK_ROUGHEN,
4253 -1 );
4255 gtk_list_store_append( model, &iter );
4256 gtk_list_store_set( model, &iter,
4257 0, _("Color paint mode"),
4258 1, _("Paint the tool's color upon selected objects"),
4259 2, INKSCAPE_ICON_OBJECT_TWEAK_PAINT,
4260 -1 );
4262 gtk_list_store_append( model, &iter );
4263 gtk_list_store_set( model, &iter,
4264 0, _("Color jitter mode"),
4265 1, _("Jitter the colors of selected objects"),
4266 2, INKSCAPE_ICON_OBJECT_TWEAK_JITTER_COLOR,
4267 -1 );
4269 gtk_list_store_append( model, &iter );
4270 gtk_list_store_set( model, &iter,
4271 0, _("Blur mode"),
4272 1, _("Blur selected objects more; with Shift, blur less"),
4273 2, INKSCAPE_ICON_OBJECT_TWEAK_BLUR,
4274 -1 );
4277 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
4278 g_object_set( act, "short_label", _("Mode:"), NULL );
4279 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
4280 g_object_set_data( holder, "mode_action", act );
4282 ege_select_one_action_set_appearance( act, "full" );
4283 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
4284 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
4285 ege_select_one_action_set_icon_column( act, 2 );
4286 ege_select_one_action_set_icon_size( act, secondarySize );
4287 ege_select_one_action_set_tooltip_column( act, 1 );
4289 gint mode = prefs->getInt("/tools/tweak/mode", 0);
4290 ege_select_one_action_set_active( act, mode );
4291 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
4293 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
4294 }
4296 guint mode = prefs->getInt("/tools/tweak/mode", 0);
4298 {
4299 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
4300 ege_output_action_set_use_markup( act, TRUE );
4301 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4302 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
4303 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
4304 g_object_set_data( holder, "tweak_channels_label", act);
4305 }
4307 {
4308 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
4309 _("Hue"),
4310 _("In color mode, act on objects' hue"),
4311 NULL,
4312 Inkscape::ICON_SIZE_DECORATION );
4313 //TRANSLATORS: "H" here stands for hue
4314 g_object_set( act, "short_label", _("H"), NULL );
4315 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4316 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
4317 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doh", true) );
4318 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
4319 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
4320 g_object_set_data( holder, "tweak_doh", act);
4321 }
4322 {
4323 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
4324 _("Saturation"),
4325 _("In color mode, act on objects' saturation"),
4326 NULL,
4327 Inkscape::ICON_SIZE_DECORATION );
4328 //TRANSLATORS: "S" here stands for Saturation
4329 g_object_set( act, "short_label", _("S"), NULL );
4330 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4331 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
4332 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dos", true) );
4333 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
4334 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
4335 g_object_set_data( holder, "tweak_dos", act );
4336 }
4337 {
4338 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
4339 _("Lightness"),
4340 _("In color mode, act on objects' lightness"),
4341 NULL,
4342 Inkscape::ICON_SIZE_DECORATION );
4343 //TRANSLATORS: "L" here stands for Lightness
4344 g_object_set( act, "short_label", _("L"), NULL );
4345 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4346 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
4347 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dol", true) );
4348 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
4349 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
4350 g_object_set_data( holder, "tweak_dol", act );
4351 }
4352 {
4353 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
4354 _("Opacity"),
4355 _("In color mode, act on objects' opacity"),
4356 NULL,
4357 Inkscape::ICON_SIZE_DECORATION );
4358 //TRANSLATORS: "O" here stands for Opacity
4359 g_object_set( act, "short_label", _("O"), NULL );
4360 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4361 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
4362 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doo", true) );
4363 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
4364 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
4365 g_object_set_data( holder, "tweak_doo", act );
4366 }
4368 { /* Fidelity */
4369 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
4370 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
4371 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
4372 _("Fidelity"), _("Fidelity:"),
4373 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
4374 "/tools/tweak/fidelity", 50,
4375 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
4376 1, 100, 1.0, 10.0,
4377 labels, values, G_N_ELEMENTS(labels),
4378 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
4379 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4380 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4381 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
4382 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
4383 g_object_set_data( holder, "tweak_fidelity", eact );
4384 }
4387 /* Use Pressure button */
4388 {
4389 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
4390 _("Pressure"),
4391 _("Use the pressure of the input device to alter the force of tweak action"),
4392 INKSCAPE_ICON_DRAW_USE_PRESSURE,
4393 Inkscape::ICON_SIZE_DECORATION );
4394 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4395 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
4396 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/usepressure", true) );
4397 }
4399 }
4402 //########################
4403 //## Spray ##
4404 //########################
4406 static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
4407 {
4408 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4409 prefs->setDouble( "/tools/spray/width", adj->value );
4410 }
4412 /*
4413 static void sp_spray_force_value_changed( GtkAdjustment * / *adj* /, GObject * / *tbl* / )
4414 {
4415 //Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4416 //prefs->setDouble( "/tools/spray/force", adj->value * 0.01 );
4417 }
4418 */
4420 static void sp_spray_mean_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
4421 {
4422 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4423 prefs->setDouble( "/tools/spray/mean", adj->value );
4424 }
4426 static void sp_spray_standard_deviation_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
4427 {
4428 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4429 prefs->setDouble( "/tools/spray/standard_deviation", adj->value );
4430 }
4432 static void sp_spray_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
4433 {
4434 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4435 prefs->setBool("/tools/spray/usepressure", gtk_toggle_action_get_active(act));
4436 }
4438 static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject */*tbl*/ )
4439 {
4440 int mode = ege_select_one_action_get_active( act );
4441 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4442 prefs->setInt("/tools/spray/mode", mode);
4443 }
4445 static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
4446 {
4447 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4448 prefs->setDouble( "/tools/spray/population", adj->value );
4449 }
4451 /*static void spray_toggle_doh (GtkToggleAction *act, gpointer ) {
4452 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4453 prefs->setBool("/tools/spray/doh", gtk_toggle_action_get_active(act));
4454 }
4455 static void spray_toggle_dos (GtkToggleAction *act, gpointer ) {
4456 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4457 prefs->setBool("/tools/spray/dos", gtk_toggle_action_get_active(act));
4458 }
4459 static void spray_toggle_dol (GtkToggleAction *act, gpointer ) {
4460 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4461 prefs->setBool("/tools/spray/dol", gtk_toggle_action_get_active(act));
4462 }
4463 static void spray_toggle_doo (GtkToggleAction *act, gpointer ) {
4464 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4465 prefs->setBool("/tools/spray/doo", gtk_toggle_action_get_active(act));
4466 }
4467 */
4468 static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4469 {
4470 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
4471 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4473 {
4474 /* Width */
4475 gchar const* labels[] = {_("(narrow spray)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad spray)")};
4476 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
4477 EgeAdjustmentAction *eact = create_adjustment_action( "SprayWidthAction",
4478 _("Width"), _("Width:"), _("The width of the spray area (relative to the visible canvas area)"),
4479 "/tools/spray/width", 15,
4480 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spray",
4481 1, 100, 1.0, 10.0,
4482 labels, values, G_N_ELEMENTS(labels),
4483 sp_spray_width_value_changed, 1, 0 );
4484 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4485 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4486 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4487 }
4489 {
4490 /* Mean */
4491 gchar const* labels[] = {_("(minimum mean)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum mean)")};
4492 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
4493 EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction",
4494 _("Mean"), _("Mean:"), _("The mean of the spray action"),
4495 "/tools/spray/mean", 20,
4496 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-mean",
4497 1, 100, 1.0, 10.0,
4498 labels, values, G_N_ELEMENTS(labels),
4499 sp_spray_mean_value_changed, 1, 0 );
4500 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4501 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4502 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4503 }
4505 {
4506 /* Standard_deviation */
4507 gchar const* labels[] = {_("(minimum standard_deviation)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum standard_deviation)")};
4508 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
4509 EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction",
4510 _("SD"), _("SD:"), _("The standard deviation of the spray action"),
4511 "/tools/spray/standard_deviation", 20,
4512 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-standard_deviation",
4513 1, 100, 1.0, 10.0,
4514 labels, values, G_N_ELEMENTS(labels),
4515 sp_spray_standard_deviation_value_changed, 1, 0 );
4516 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4517 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4518 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4519 }
4521 /* Mode */
4522 {
4523 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
4525 GtkTreeIter iter;
4526 gtk_list_store_append( model, &iter );
4527 gtk_list_store_set( model, &iter,
4528 0, _("Spray with copies"),
4529 1, _("Spray copies of the initial selection"),
4530 2, INKSCAPE_ICON_SPRAY_COPY_MODE,
4531 -1 );
4533 gtk_list_store_append( model, &iter );
4534 gtk_list_store_set( model, &iter,
4535 0, _("Spray with clones"),
4536 1, _("Spray clones of the initial selection"),
4537 2, INKSCAPE_ICON_SPRAY_CLONE_MODE,
4538 -1 );
4540 gtk_list_store_append( model, &iter );
4541 gtk_list_store_set( model, &iter,
4542 0, _("Spray single path"),
4543 1, _("Spray objects in a single path"),
4544 2, INKSCAPE_ICON_SPRAY_UNION_MODE,
4545 -1 );
4547 EgeSelectOneAction* act = ege_select_one_action_new( "SprayModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
4548 g_object_set( act, "short_label", _("Mode:"), NULL );
4549 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
4550 g_object_set_data( holder, "mode_action", act );
4552 ege_select_one_action_set_appearance( act, "full" );
4553 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
4554 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
4555 ege_select_one_action_set_icon_column( act, 2 );
4556 ege_select_one_action_set_icon_size( act, secondarySize );
4557 ege_select_one_action_set_tooltip_column( act, 1 );
4559 gint mode = prefs->getInt("/tools/spray/mode", 0);
4560 ege_select_one_action_set_active( act, mode );
4561 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_spray_mode_changed), holder );
4563 g_object_set_data( G_OBJECT(holder), "spray_tool_mode", act);
4564 }
4566 { /* Population */
4567 gchar const* labels[] = {_("(low population)"), 0, 0, _("(default)"), 0, 0, _("(high population)")};
4568 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
4569 EgeAdjustmentAction *eact = create_adjustment_action( "SprayPopulationAction",
4570 _("Population"), _("Population:"),
4571 _("This setting adjusts the number of items sprayed"),
4572 "/tools/spray/population", 50,
4573 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-population",
4574 1, 100, 1.0, 10.0,
4575 labels, values, G_N_ELEMENTS(labels),
4576 sp_spray_population_value_changed, 1, 0 );
4577 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4578 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4579 g_object_set_data( holder, "spray_population", eact );
4580 }
4582 /* Use Pressure button */
4583 {
4584 InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction",
4585 _("Pressure"),
4586 _("Use the pressure of the input device to alter the force of spray action"),
4587 "use_pressure",
4588 Inkscape::ICON_SIZE_DECORATION );
4589 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4590 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_spray_pressure_state_changed), NULL);
4591 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/usepressure", true) );
4592 }
4593 }
4596 //########################
4597 //## Calligraphy ##
4598 //########################
4599 static void update_presets_list (GObject *tbl)
4600 {
4601 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4602 if (g_object_get_data(tbl, "presets_blocked"))
4603 return;
4605 EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
4606 if (!sel) {
4607 // WTF!? This will cause a segfault if ever reached
4608 //ege_select_one_action_set_active(sel, 0);
4609 return;
4610 }
4612 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
4614 int ege_index = 1;
4615 for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++ege_index) {
4616 bool match = true;
4618 std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(*i);
4619 for (std::vector<Inkscape::Preferences::Entry>::iterator j = preset.begin(); j != preset.end(); ++j) {
4620 Glib::ustring entry_name = j->getEntryName();
4621 if (entry_name == "id" || entry_name == "name") continue;
4623 void *widget = g_object_get_data(tbl, entry_name.data());
4624 if (widget) {
4625 if (GTK_IS_ADJUSTMENT(widget)) {
4626 double v = j->getDouble();
4627 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
4628 //std::cout << "compared adj " << attr_name << gtk_adjustment_get_value(adj) << " to " << v << "\n";
4629 if (fabs(gtk_adjustment_get_value(adj) - v) > 1e-6) {
4630 match = false;
4631 break;
4632 }
4633 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
4634 bool v = j->getBool();
4635 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
4636 //std::cout << "compared toggle " << attr_name << gtk_toggle_action_get_active(toggle) << " to " << v << "\n";
4637 if ( static_cast<bool>(gtk_toggle_action_get_active(toggle)) != v ) {
4638 match = false;
4639 break;
4640 }
4641 }
4642 }
4643 }
4645 if (match) {
4646 // newly added item is at the same index as the
4647 // save command, so we need to change twice for it to take effect
4648 ege_select_one_action_set_active(sel, 0);
4649 ege_select_one_action_set_active(sel, ege_index); // one-based index
4650 return;
4651 }
4652 }
4654 // no match found
4655 ege_select_one_action_set_active(sel, 0);
4656 }
4658 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
4659 {
4660 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4661 prefs->setDouble( "/tools/calligraphic/mass", adj->value );
4662 update_presets_list(tbl);
4663 }
4665 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
4666 {
4667 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4668 prefs->setDouble( "/tools/calligraphic/wiggle", adj->value );
4669 update_presets_list(tbl);
4670 }
4672 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
4673 {
4674 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4675 prefs->setDouble( "/tools/calligraphic/angle", adj->value );
4676 update_presets_list(tbl);
4677 }
4679 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
4680 {
4681 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4682 prefs->setDouble( "/tools/calligraphic/width", adj->value );
4683 update_presets_list(tbl);
4684 }
4686 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
4687 {
4688 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4689 prefs->setDouble("/tools/calligraphic/thinning", adj->value );
4690 update_presets_list(tbl);
4691 }
4693 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
4694 {
4695 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4696 prefs->setDouble( "/tools/calligraphic/flatness", adj->value );
4697 update_presets_list(tbl);
4698 }
4700 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
4701 {
4702 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4703 prefs->setDouble( "/tools/calligraphic/tremor", adj->value );
4704 update_presets_list(tbl);
4705 }
4707 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
4708 {
4709 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4710 prefs->setDouble( "/tools/calligraphic/cap_rounding", adj->value );
4711 update_presets_list(tbl);
4712 }
4714 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, GObject* tbl )
4715 {
4716 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4717 prefs->setBool("/tools/calligraphic/usepressure", gtk_toggle_action_get_active( act ));
4718 update_presets_list(tbl);
4719 }
4721 static void sp_ddc_trace_background_changed( GtkToggleAction *act, GObject* tbl )
4722 {
4723 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4724 prefs->setBool("/tools/calligraphic/tracebackground", gtk_toggle_action_get_active( act ));
4725 update_presets_list(tbl);
4726 }
4728 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject* tbl )
4729 {
4730 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4731 GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle_action"));
4732 prefs->setBool("/tools/calligraphic/usetilt", gtk_toggle_action_get_active( act ));
4733 update_presets_list(tbl);
4734 if (calligraphy_angle )
4735 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
4736 }
4739 static gchar const *const widget_names[] = {
4740 "width",
4741 "mass",
4742 "wiggle",
4743 "angle",
4744 "thinning",
4745 "tremor",
4746 "flatness",
4747 "cap_rounding",
4748 "usepressure",
4749 "tracebackground",
4750 "usetilt"
4751 };
4754 static void sp_dcc_build_presets_list(GObject *tbl)
4755 {
4756 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE));
4758 EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "profile_selector"));
4759 GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
4760 gtk_list_store_clear (model);
4762 {
4763 GtkTreeIter iter;
4764 gtk_list_store_append( model, &iter );
4765 gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 );
4766 }
4768 // iterate over all presets to populate the list
4769 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4770 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
4771 int ii=1;
4773 for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i) {
4774 GtkTreeIter iter;
4775 Glib::ustring preset_name = prefs->getString(*i + "/name");
4776 gtk_list_store_append( model, &iter );
4777 gtk_list_store_set( model, &iter, 0, _(preset_name.data()), 1, ii++, -1 );
4778 }
4780 {
4781 GtkTreeIter iter;
4782 gtk_list_store_append( model, &iter );
4783 gtk_list_store_set( model, &iter, 0, _("Save..."), 1, ii, -1 );
4784 g_object_set_data(tbl, "save_presets_index", GINT_TO_POINTER(ii));
4785 }
4787 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
4789 update_presets_list (tbl);
4790 }
4792 static void sp_dcc_save_profile (GtkWidget */*widget*/, GObject *tbl)
4793 {
4794 using Inkscape::UI::Dialog::CalligraphicProfileRename;
4795 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4796 SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop" );
4797 if (! desktop) return;
4799 if (g_object_get_data(tbl, "presets_blocked"))
4800 return;
4802 CalligraphicProfileRename::show(desktop);
4803 if ( !CalligraphicProfileRename::applied()) {
4804 // dialog cancelled
4805 update_presets_list (tbl);
4806 return;
4807 }
4808 Glib::ustring profile_name = CalligraphicProfileRename::getProfileName();
4810 if (profile_name.empty()) {
4811 // empty name entered
4812 update_presets_list (tbl);
4813 return;
4814 }
4816 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(TRUE));
4818 // If there's a preset with the given name, find it and set save_path appropriately
4819 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
4820 int total_presets = presets.size();
4821 int new_index = -1;
4822 Glib::ustring save_path; // profile pref path without a trailing slash
4824 int temp_index = 0;
4825 for (std::vector<Glib::ustring>::iterator i = presets.begin(); i != presets.end(); ++i, ++temp_index) {
4826 Glib::ustring name = prefs->getString(*i + "/name");
4827 if (!name.empty() && profile_name == name) {
4828 new_index = temp_index;
4829 save_path = *i;
4830 break;
4831 }
4832 }
4834 if (new_index == -1) {
4835 // no preset with this name, create
4836 new_index = total_presets + 1;
4837 gchar *profile_id = g_strdup_printf("/dcc%d", new_index);
4838 save_path = Glib::ustring("/tools/calligraphic/preset") + profile_id;
4839 g_free(profile_id);
4840 }
4842 for (unsigned i = 0; i < G_N_ELEMENTS(widget_names); ++i) {
4843 gchar const *const widget_name = widget_names[i];
4844 void *widget = g_object_get_data(tbl, widget_name);
4845 if (widget) {
4846 if (GTK_IS_ADJUSTMENT(widget)) {
4847 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
4848 prefs->setDouble(save_path + "/" + widget_name, gtk_adjustment_get_value(adj));
4849 //std::cout << "wrote adj " << widget_name << ": " << v << "\n";
4850 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
4851 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
4852 prefs->setBool(save_path + "/" + widget_name, gtk_toggle_action_get_active(toggle));
4853 //std::cout << "wrote tog " << widget_name << ": " << v << "\n";
4854 } else {
4855 g_warning("Unknown widget type for preset: %s\n", widget_name);
4856 }
4857 } else {
4858 g_warning("Bad key when writing preset: %s\n", widget_name);
4859 }
4860 }
4861 prefs->setString(save_path + "/name", profile_name);
4863 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
4864 sp_dcc_build_presets_list (tbl);
4865 }
4868 static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject* tbl) {
4870 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4872 gint preset_index = ege_select_one_action_get_active( act );
4873 // This is necessary because EgeSelectOneAction spams us with GObject "changed" signal calls
4874 // even when the preset is not changed. It would be good to replace it with something more
4875 // modern. Index 0 means "No preset", so we don't do anything.
4876 if (preset_index == 0) return;
4878 gint save_presets_index = GPOINTER_TO_INT(g_object_get_data(tbl, "save_presets_index"));
4880 if (preset_index == save_presets_index) {
4881 // this is the Save command
4882 sp_dcc_save_profile(NULL, tbl);
4883 return;
4884 }
4886 if (g_object_get_data(tbl, "presets_blocked"))
4887 return;
4889 // preset_index is one-based so we subtract 1
4890 std::vector<Glib::ustring> presets = prefs->getAllDirs("/tools/calligraphic/preset");
4891 Glib::ustring preset_path = presets.at(preset_index - 1);
4893 if (!preset_path.empty()) {
4894 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
4896 std::vector<Inkscape::Preferences::Entry> preset = prefs->getAllEntries(preset_path);
4898 // Shouldn't this be std::map?
4899 for (std::vector<Inkscape::Preferences::Entry>::iterator i = preset.begin(); i != preset.end(); ++i) {
4900 Glib::ustring entry_name = i->getEntryName();
4901 if (entry_name == "id" || entry_name == "name") continue;
4902 void *widget = g_object_get_data(tbl, entry_name.data());
4903 if (widget) {
4904 if (GTK_IS_ADJUSTMENT(widget)) {
4905 GtkAdjustment* adj = static_cast<GtkAdjustment *>(widget);
4906 gtk_adjustment_set_value(adj, i->getDouble());
4907 //std::cout << "set adj " << attr_name << " to " << v << "\n";
4908 } else if (GTK_IS_TOGGLE_ACTION(widget)) {
4909 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(widget);
4910 gtk_toggle_action_set_active(toggle, i->getBool());
4911 //std::cout << "set toggle " << attr_name << " to " << v << "\n";
4912 } else {
4913 g_warning("Unknown widget type for preset: %s\n", entry_name.data());
4914 }
4915 } else {
4916 g_warning("Bad key found in a preset record: %s\n", entry_name.data());
4917 }
4918 }
4919 g_object_set_data(tbl, "presets_blocked", GINT_TO_POINTER(FALSE));
4920 }
4921 }
4924 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4925 {
4926 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
4927 {
4928 g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(TRUE));
4930 EgeAdjustmentAction* calligraphy_angle = 0;
4932 {
4933 /* Width */
4934 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
4935 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
4936 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
4937 _("Pen Width"), _("Width:"),
4938 _("The width of the calligraphic pen (relative to the visible canvas area)"),
4939 "/tools/calligraphic/width", 15,
4940 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
4941 1, 100, 1.0, 10.0,
4942 labels, values, G_N_ELEMENTS(labels),
4943 sp_ddc_width_value_changed, 1, 0 );
4944 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
4945 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4946 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4947 }
4949 {
4950 /* Thinning */
4951 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
4952 gdouble values[] = {-100, -40, -20, -10, 0, 10, 20, 40, 100};
4953 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
4954 _("Stroke Thinning"), _("Thinning:"),
4955 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
4956 "/tools/calligraphic/thinning", 10,
4957 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4958 -100, 100, 1, 10.0,
4959 labels, values, G_N_ELEMENTS(labels),
4960 sp_ddc_velthin_value_changed, 1, 0);
4961 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4962 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4963 }
4965 {
4966 /* Angle */
4967 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
4968 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
4969 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
4970 _("Pen Angle"), _("Angle:"),
4971 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
4972 "/tools/calligraphic/angle", 30,
4973 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
4974 -90.0, 90.0, 1.0, 10.0,
4975 labels, values, G_N_ELEMENTS(labels),
4976 sp_ddc_angle_value_changed, 1, 0 );
4977 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4978 g_object_set_data( holder, "angle_action", eact );
4979 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4980 calligraphy_angle = eact;
4981 }
4983 {
4984 /* Fixation */
4985 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
4986 gdouble values[] = {0, 20, 40, 60, 90, 100};
4987 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
4988 _("Fixation"), _("Fixation:"),
4989 _("Angle behavior (0 = nib always perpendicular to stroke direction, 100 = fixed angle)"),
4990 "/tools/calligraphic/flatness", 90,
4991 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
4992 0.0, 100, 1.0, 10.0,
4993 labels, values, G_N_ELEMENTS(labels),
4994 sp_ddc_flatness_value_changed, 1, 0);
4995 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4996 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
4997 }
4999 {
5000 /* Cap Rounding */
5001 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
5002 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
5003 // TRANSLATORS: "cap" means "end" (both start and finish) here
5004 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
5005 _("Cap rounding"), _("Caps:"),
5006 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
5007 "/tools/calligraphic/cap_rounding", 0.0,
5008 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
5009 0.0, 5.0, 0.01, 0.1,
5010 labels, values, G_N_ELEMENTS(labels),
5011 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
5012 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5013 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
5014 }
5016 {
5017 /* Tremor */
5018 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
5019 gdouble values[] = {0, 10, 20, 40, 60, 100};
5020 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
5021 _("Stroke Tremor"), _("Tremor:"),
5022 _("Increase to make strokes rugged and trembling"),
5023 "/tools/calligraphic/tremor", 0.0,
5024 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
5025 0.0, 100, 1, 10.0,
5026 labels, values, G_N_ELEMENTS(labels),
5027 sp_ddc_tremor_value_changed, 1, 0);
5029 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
5030 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5031 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
5032 }
5034 {
5035 /* Wiggle */
5036 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
5037 gdouble values[] = {0, 20, 40, 60, 100};
5038 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
5039 _("Pen Wiggle"), _("Wiggle:"),
5040 _("Increase to make the pen waver and wiggle"),
5041 "/tools/calligraphic/wiggle", 0.0,
5042 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
5043 0.0, 100, 1, 10.0,
5044 labels, values, G_N_ELEMENTS(labels),
5045 sp_ddc_wiggle_value_changed, 1, 0);
5046 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
5047 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5048 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
5049 }
5051 {
5052 /* Mass */
5053 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
5054 gdouble values[] = {0.0, 2, 10, 20, 50, 100};
5055 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
5056 _("Pen Mass"), _("Mass:"),
5057 _("Increase to make the pen drag behind, as if slowed by inertia"),
5058 "/tools/calligraphic/mass", 2.0,
5059 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
5060 0.0, 100, 1, 10.0,
5061 labels, values, G_N_ELEMENTS(labels),
5062 sp_ddc_mass_value_changed, 1, 0);
5063 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
5064 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5065 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
5066 }
5069 /* Trace Background button */
5070 {
5071 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
5072 _("Trace Background"),
5073 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
5074 INKSCAPE_ICON_DRAW_TRACE_BACKGROUND,
5075 Inkscape::ICON_SIZE_DECORATION );
5076 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5077 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), holder);
5078 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/tracebackground", false) );
5079 g_object_set_data( holder, "tracebackground", act );
5080 }
5082 /* Use Pressure button */
5083 {
5084 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
5085 _("Pressure"),
5086 _("Use the pressure of the input device to alter the width of the pen"),
5087 INKSCAPE_ICON_DRAW_USE_PRESSURE,
5088 Inkscape::ICON_SIZE_DECORATION );
5089 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5090 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), holder);
5091 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/usepressure", true) );
5092 g_object_set_data( holder, "usepressure", act );
5093 }
5095 /* Use Tilt button */
5096 {
5097 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
5098 _("Tilt"),
5099 _("Use the tilt of the input device to alter the angle of the pen's nib"),
5100 INKSCAPE_ICON_DRAW_USE_TILT,
5101 Inkscape::ICON_SIZE_DECORATION );
5102 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5103 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), holder );
5104 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs->getBool("/tools/calligraphic/usetilt", true) );
5105 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/calligraphic/usetilt", true) );
5106 g_object_set_data( holder, "usetilt", act );
5107 }
5109 /*calligraphic profile */
5110 {
5111 GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
5112 EgeSelectOneAction* act1 = ege_select_one_action_new ("SetProfileAction", "" , (_("Choose a preset")), NULL, GTK_TREE_MODEL(model));
5113 ege_select_one_action_set_appearance (act1, "compact");
5114 g_object_set_data (holder, "profile_selector", act1 );
5116 g_object_set_data(holder, "presets_blocked", GINT_TO_POINTER(FALSE));
5118 sp_dcc_build_presets_list (holder);
5120 g_signal_connect(G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder);
5121 gtk_action_group_add_action(mainActions, GTK_ACTION(act1));
5122 }
5123 }
5124 }
5127 //########################
5128 //## Circle / Arc ##
5129 //########################
5131 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
5132 {
5133 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
5134 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
5136 if (v1 == 0 && v2 == 0) {
5137 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
5138 gtk_action_set_sensitive( ocb, FALSE );
5139 gtk_action_set_sensitive( make_whole, FALSE );
5140 }
5141 } else {
5142 gtk_action_set_sensitive( ocb, TRUE );
5143 gtk_action_set_sensitive( make_whole, TRUE );
5144 }
5145 }
5147 static void
5148 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
5149 {
5150 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
5152 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
5153 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5154 prefs->setDouble(Glib::ustring("/tools/shapes/arc/") + value_name, adj->value);
5155 }
5157 // quit if run by the attr_changed listener
5158 if (g_object_get_data( tbl, "freeze" )) {
5159 return;
5160 }
5162 // in turn, prevent listener from responding
5163 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
5165 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
5167 bool modmade = false;
5168 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
5169 items != NULL;
5170 items = items->next)
5171 {
5172 SPItem *item = SP_ITEM(items->data);
5174 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
5176 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
5177 SPArc *arc = SP_ARC(item);
5179 if (!strcmp(value_name, "start"))
5180 ge->start = (adj->value * M_PI)/ 180;
5181 else
5182 ge->end = (adj->value * M_PI)/ 180;
5184 sp_genericellipse_normalize(ge);
5185 ((SPObject *)arc)->updateRepr();
5186 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
5188 modmade = true;
5189 }
5190 }
5192 g_free(namespaced_name);
5194 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
5196 sp_arctb_sensitivize( tbl, adj->value, other->value );
5198 if (modmade) {
5199 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
5200 _("Arc: Change start/end"));
5201 }
5203 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5204 }
5207 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
5208 {
5209 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
5210 }
5212 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
5213 {
5214 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
5215 }
5218 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
5219 {
5220 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
5221 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
5222 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5223 prefs->setBool("/tools/shapes/arc/open", ege_select_one_action_get_active(act) != 0);
5224 }
5226 // quit if run by the attr_changed listener
5227 if (g_object_get_data( tbl, "freeze" )) {
5228 return;
5229 }
5231 // in turn, prevent listener from responding
5232 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
5234 bool modmade = false;
5236 if ( ege_select_one_action_get_active(act) != 0 ) {
5237 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
5238 items != NULL;
5239 items = items->next)
5240 {
5241 if (SP_IS_ARC((SPItem *) items->data)) {
5242 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
5243 repr->setAttribute("sodipodi:open", "true");
5244 SP_OBJECT((SPItem *) items->data)->updateRepr();
5245 modmade = true;
5246 }
5247 }
5248 } else {
5249 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
5250 items != NULL;
5251 items = items->next)
5252 {
5253 if (SP_IS_ARC((SPItem *) items->data)) {
5254 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
5255 repr->setAttribute("sodipodi:open", NULL);
5256 SP_OBJECT((SPItem *) items->data)->updateRepr();
5257 modmade = true;
5258 }
5259 }
5260 }
5262 if (modmade) {
5263 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
5264 _("Arc: Change open/closed"));
5265 }
5267 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5268 }
5270 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
5271 {
5272 GtkAdjustment *adj;
5273 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
5274 gtk_adjustment_set_value(adj, 0.0);
5275 gtk_adjustment_value_changed(adj);
5277 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
5278 gtk_adjustment_set_value(adj, 0.0);
5279 gtk_adjustment_value_changed(adj);
5281 spinbutton_defocus( GTK_OBJECT(obj) );
5282 }
5284 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
5285 gchar const */*old_value*/, gchar const */*new_value*/,
5286 bool /*is_interactive*/, gpointer data)
5287 {
5288 GObject *tbl = G_OBJECT(data);
5290 // quit if run by the _changed callbacks
5291 if (g_object_get_data( tbl, "freeze" )) {
5292 return;
5293 }
5295 // in turn, prevent callbacks from responding
5296 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
5298 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
5299 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
5301 GtkAdjustment *adj1,*adj2;
5302 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
5303 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
5304 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
5305 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
5307 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
5309 char const *openstr = NULL;
5310 openstr = repr->attribute("sodipodi:open");
5311 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
5313 if (openstr) {
5314 ege_select_one_action_set_active( ocb, 1 );
5315 } else {
5316 ege_select_one_action_set_active( ocb, 0 );
5317 }
5319 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5320 }
5322 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
5323 NULL, /* child_added */
5324 NULL, /* child_removed */
5325 arc_tb_event_attr_changed,
5326 NULL, /* content_changed */
5327 NULL /* order_changed */
5328 };
5331 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
5332 {
5333 int n_selected = 0;
5334 Inkscape::XML::Node *repr = NULL;
5336 purge_repr_listener( tbl, tbl );
5338 for (GSList const *items = selection->itemList();
5339 items != NULL;
5340 items = items->next)
5341 {
5342 if (SP_IS_ARC((SPItem *) items->data)) {
5343 n_selected++;
5344 repr = SP_OBJECT_REPR((SPItem *) items->data);
5345 }
5346 }
5348 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
5350 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
5351 if (n_selected == 0) {
5352 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
5353 } else if (n_selected == 1) {
5354 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
5355 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
5357 if (repr) {
5358 g_object_set_data( tbl, "repr", repr );
5359 Inkscape::GC::anchor(repr);
5360 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
5361 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
5362 }
5363 } else {
5364 // FIXME: implement averaging of all parameters for multiple selected
5365 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
5366 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
5367 sp_arctb_sensitivize( tbl, 1, 0 );
5368 }
5369 }
5372 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5373 {
5374 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5376 EgeAdjustmentAction* eact = 0;
5377 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
5380 {
5381 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
5382 ege_output_action_set_use_markup( act, TRUE );
5383 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5384 g_object_set_data( holder, "mode_action", act );
5385 }
5387 /* Start */
5388 {
5389 eact = create_adjustment_action( "ArcStartAction",
5390 _("Start"), _("Start:"),
5391 _("The angle (in degrees) from the horizontal to the arc's start point"),
5392 "/tools/shapes/arc/start", 0.0,
5393 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
5394 -360.0, 360.0, 1.0, 10.0,
5395 0, 0, 0,
5396 sp_arctb_start_value_changed);
5397 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5398 }
5400 /* End */
5401 {
5402 eact = create_adjustment_action( "ArcEndAction",
5403 _("End"), _("End:"),
5404 _("The angle (in degrees) from the horizontal to the arc's end point"),
5405 "/tools/shapes/arc/end", 0.0,
5406 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
5407 -360.0, 360.0, 1.0, 10.0,
5408 0, 0, 0,
5409 sp_arctb_end_value_changed);
5410 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5411 }
5413 /* Segments / Pie checkbox */
5414 {
5415 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
5417 GtkTreeIter iter;
5418 gtk_list_store_append( model, &iter );
5419 gtk_list_store_set( model, &iter,
5420 0, _("Closed arc"),
5421 1, _("Switch to segment (closed shape with two radii)"),
5422 2, INKSCAPE_ICON_DRAW_ELLIPSE_SEGMENT,
5423 -1 );
5425 gtk_list_store_append( model, &iter );
5426 gtk_list_store_set( model, &iter,
5427 0, _("Open Arc"),
5428 1, _("Switch to arc (unclosed shape)"),
5429 2, INKSCAPE_ICON_DRAW_ELLIPSE_ARC,
5430 -1 );
5432 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
5433 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
5434 g_object_set_data( holder, "open_action", act );
5436 ege_select_one_action_set_appearance( act, "full" );
5437 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
5438 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
5439 ege_select_one_action_set_icon_column( act, 2 );
5440 ege_select_one_action_set_icon_size( act, secondarySize );
5441 ege_select_one_action_set_tooltip_column( act, 1 );
5443 bool isClosed = !prefs->getBool("/tools/shapes/arc/open", false);
5444 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
5445 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
5446 }
5448 /* Make Whole */
5449 {
5450 InkAction* inky = ink_action_new( "ArcResetAction",
5451 _("Make whole"),
5452 _("Make the shape a whole ellipse, not arc or segment"),
5453 INKSCAPE_ICON_DRAW_ELLIPSE_WHOLE,
5454 secondarySize );
5455 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
5456 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5457 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
5458 g_object_set_data( holder, "make_whole", inky );
5459 }
5461 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
5462 // sensitivize make whole and open checkbox
5463 {
5464 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
5465 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
5466 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
5467 }
5470 sigc::connection *connection = new sigc::connection(
5471 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
5472 );
5473 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
5474 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
5475 }
5480 // toggle button callbacks and updaters
5482 //########################
5483 //## Dropper ##
5484 //########################
5486 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
5487 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5488 prefs->setInt( "/tools/dropper/pick", gtk_toggle_action_get_active( act ) );
5489 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
5490 if ( set_action ) {
5491 if ( gtk_toggle_action_get_active( act ) ) {
5492 gtk_action_set_sensitive( set_action, TRUE );
5493 } else {
5494 gtk_action_set_sensitive( set_action, FALSE );
5495 }
5496 }
5498 spinbutton_defocus(GTK_OBJECT(tbl));
5499 }
5501 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
5502 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5503 prefs->setBool( "/tools/dropper/setalpha", gtk_toggle_action_get_active( act ) );
5504 spinbutton_defocus(GTK_OBJECT(tbl));
5505 }
5508 /**
5509 * Dropper auxiliary toolbar construction and setup.
5510 *
5511 * TODO: Would like to add swatch of current color.
5512 * TODO: Add queue of last 5 or so colors selected with new swatches so that
5513 * can drag and drop places. Will provide a nice mixing palette.
5514 */
5515 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
5516 {
5517 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5518 gint pickAlpha = prefs->getInt( "/tools/dropper/pick", 1 );
5520 {
5521 EgeOutputAction* act = ege_output_action_new( "DropperOpacityAction", _("Opacity:"), "", 0 );
5522 ege_output_action_set_use_markup( act, TRUE );
5523 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5524 }
5526 {
5527 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
5528 _("Pick opacity"),
5529 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
5530 NULL,
5531 Inkscape::ICON_SIZE_DECORATION );
5532 g_object_set( act, "short_label", _("Pick"), NULL );
5533 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5534 g_object_set_data( holder, "pick_action", act );
5535 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
5536 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
5537 }
5539 {
5540 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
5541 _("Assign opacity"),
5542 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
5543 NULL,
5544 Inkscape::ICON_SIZE_DECORATION );
5545 g_object_set( act, "short_label", _("Assign"), NULL );
5546 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5547 g_object_set_data( holder, "set_action", act );
5548 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/dropper/setalpha", true) );
5549 // make sure it's disabled if we're not picking alpha
5550 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
5551 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
5552 }
5553 }
5556 //########################
5557 //## LPETool ##
5558 //########################
5560 // the subtools from which the toolbar is built automatically are listed in lpe-tool-context.h
5562 // this is called when the mode is changed via the toolbar (i.e., one of the subtool buttons is pressed)
5563 static void sp_lpetool_mode_changed(EgeSelectOneAction *act, GObject *tbl)
5564 {
5565 using namespace Inkscape::LivePathEffect;
5567 SPDesktop *desktop = (SPDesktop *) g_object_get_data(tbl, "desktop");
5568 SPEventContext *ec = desktop->event_context;
5569 if (!SP_IS_LPETOOL_CONTEXT(ec)) {
5570 return;
5571 }
5573 // only take action if run by the attr_changed listener
5574 if (!g_object_get_data(tbl, "freeze")) {
5575 // in turn, prevent listener from responding
5576 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
5578 gint mode = ege_select_one_action_get_active(act);
5579 EffectType type = lpesubtools[mode].type;
5581 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
5582 bool success = lpetool_try_construction(lc, type);
5583 if (success) {
5584 // since the construction was already performed, we set the state back to inactive
5585 ege_select_one_action_set_active(act, 0);
5586 mode = 0;
5587 } else {
5588 // switch to the chosen subtool
5589 SP_LPETOOL_CONTEXT(desktop->event_context)->mode = type;
5590 }
5592 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
5593 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5594 prefs->setInt( "/tools/lpetool/mode", mode );
5595 }
5597 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE));
5598 }
5599 }
5601 void sp_lpetool_toolbox_sel_modified(Inkscape::Selection *selection, guint /*flags*/, GObject */*tbl*/)
5602 {
5603 SPEventContext *ec = selection->desktop()->event_context;
5604 if (!SP_IS_LPETOOL_CONTEXT(ec))
5605 return;
5607 lpetool_update_measuring_items(SP_LPETOOL_CONTEXT(ec));
5608 }
5610 void
5611 sp_lpetool_toolbox_sel_changed(Inkscape::Selection *selection, GObject *tbl)
5612 {
5613 using namespace Inkscape::LivePathEffect;
5614 SPEventContext *ec = selection->desktop()->event_context;
5615 if (!SP_IS_LPETOOL_CONTEXT(ec))
5616 return;
5617 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(ec);
5619 lpetool_delete_measuring_items(lc);
5620 lpetool_create_measuring_items(lc, selection);
5622 // activate line segment combo box if a single item with LPELineSegment is selected
5623 GtkAction* w = GTK_ACTION(g_object_get_data(tbl, "lpetool_line_segment_action"));
5624 SPItem *item = selection->singleItem();
5625 if (item && SP_IS_LPE_ITEM(item) && lpetool_item_has_construction(lc, item)) {
5626 SPLPEItem *lpeitem = SP_LPE_ITEM(item);
5627 Effect* lpe = sp_lpe_item_get_current_lpe(lpeitem);
5628 if (lpe && lpe->effectType() == LINE_SEGMENT) {
5629 LPELineSegment *lpels = static_cast<LPELineSegment*>(lpe);
5630 g_object_set_data(tbl, "currentlpe", lpe);
5631 g_object_set_data(tbl, "currentlpeitem", lpeitem);
5632 gtk_action_set_sensitive(w, TRUE);
5633 ege_select_one_action_set_active(EGE_SELECT_ONE_ACTION(w), lpels->end_type.get_value());
5634 } else {
5635 g_object_set_data(tbl, "currentlpe", NULL);
5636 g_object_set_data(tbl, "currentlpeitem", NULL);
5637 gtk_action_set_sensitive(w, FALSE);
5638 }
5639 } else {
5640 g_object_set_data(tbl, "currentlpe", NULL);
5641 g_object_set_data(tbl, "currentlpeitem", NULL);
5642 gtk_action_set_sensitive(w, FALSE);
5643 }
5644 }
5646 static void
5647 lpetool_toggle_show_bbox (GtkToggleAction *act, gpointer data) {
5648 SPDesktop *desktop = static_cast<SPDesktop *>(data);
5649 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5651 bool show = gtk_toggle_action_get_active( act );
5652 prefs->setBool("/tools/lpetool/show_bbox", show);
5654 if (tools_isactive(desktop, TOOLS_LPETOOL)) {
5655 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
5656 lpetool_context_reset_limiting_bbox(lc);
5657 }
5658 }
5660 static void
5661 lpetool_toggle_show_measuring_info (GtkToggleAction *act, GObject *tbl) {
5662 SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop"));
5663 if (!tools_isactive(desktop, TOOLS_LPETOOL))
5664 return;
5666 GtkAction *unitact = static_cast<GtkAction*>(g_object_get_data(tbl, "lpetool_units_action"));
5667 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
5668 if (tools_isactive(desktop, TOOLS_LPETOOL)) {
5669 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5670 bool show = gtk_toggle_action_get_active( act );
5671 prefs->setBool("/tools/lpetool/show_measuring_info", show);
5672 lpetool_show_measuring_info(lc, show);
5673 gtk_action_set_sensitive(GTK_ACTION(unitact), show);
5674 }
5675 }
5677 static void lpetool_unit_changed(GtkAction* /*act*/, GObject* tbl) {
5678 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker"));
5679 SPUnit const *unit = tracker->getActiveUnit();
5680 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5681 prefs->setInt("/tools/lpetool/unitid", unit->unit_id);
5683 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
5684 if (SP_IS_LPETOOL_CONTEXT(desktop->event_context)) {
5685 SPLPEToolContext *lc = SP_LPETOOL_CONTEXT(desktop->event_context);
5686 lpetool_delete_measuring_items(lc);
5687 lpetool_create_measuring_items(lc);
5688 }
5689 }
5691 static void
5692 lpetool_toggle_set_bbox (GtkToggleAction *act, gpointer data) {
5693 SPDesktop *desktop = static_cast<SPDesktop *>(data);
5694 Inkscape::Selection *selection = desktop->selection;
5696 Geom::OptRect bbox = selection->bounds();
5698 if (bbox) {
5699 Geom::Point A(bbox->min());
5700 Geom::Point B(bbox->max());
5702 A *= desktop->doc2dt();
5703 B *= desktop->doc2dt();
5705 // TODO: should we provide a way to store points in prefs?
5706 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5707 prefs->setDouble("/tools/lpetool/bbox_upperleftx", A[Geom::X]);
5708 prefs->setDouble("/tools/lpetool/bbox_upperlefty", A[Geom::Y]);
5709 prefs->setDouble("/tools/lpetool/bbox_lowerrightx", B[Geom::X]);
5710 prefs->setDouble("/tools/lpetool/bbox_lowerrighty", B[Geom::Y]);
5712 lpetool_context_reset_limiting_bbox(SP_LPETOOL_CONTEXT(desktop->event_context));
5713 }
5715 gtk_toggle_action_set_active(act, false);
5716 }
5718 static void
5719 sp_line_segment_build_list(GObject *tbl)
5720 {
5721 g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(TRUE));
5723 EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(tbl, "lpetool_line_segment_action"));
5724 GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
5725 gtk_list_store_clear (model);
5727 // TODO: we add the entries of rht combo box manually; later this should be done automatically
5728 {
5729 GtkTreeIter iter;
5730 gtk_list_store_append( model, &iter );
5731 gtk_list_store_set( model, &iter, 0, _("Closed"), 1, 0, -1 );
5732 gtk_list_store_append( model, &iter );
5733 gtk_list_store_set( model, &iter, 0, _("Open start"), 1, 1, -1 );
5734 gtk_list_store_append( model, &iter );
5735 gtk_list_store_set( model, &iter, 0, _("Open end"), 1, 2, -1 );
5736 gtk_list_store_append( model, &iter );
5737 gtk_list_store_set( model, &iter, 0, _("Open both"), 1, 3, -1 );
5738 }
5740 g_object_set_data(tbl, "line_segment_list_blocked", GINT_TO_POINTER(FALSE));
5741 }
5743 static void
5744 sp_lpetool_change_line_segment_type(EgeSelectOneAction* act, GObject* tbl) {
5745 using namespace Inkscape::LivePathEffect;
5747 // quit if run by the attr_changed listener
5748 if (g_object_get_data(tbl, "freeze")) {
5749 return;
5750 }
5752 // in turn, prevent listener from responding
5753 g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE));
5755 LPELineSegment *lpe = static_cast<LPELineSegment *>(g_object_get_data(tbl, "currentlpe"));
5756 SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem"));
5757 if (lpeitem) {
5758 SPLPEItem *lpeitem = static_cast<SPLPEItem *>(g_object_get_data(tbl, "currentlpeitem"));
5759 lpe->end_type.param_set_value(static_cast<Inkscape::LivePathEffect::EndType>(ege_select_one_action_get_active(act)));
5760 sp_lpe_item_update_patheffect(lpeitem, true, true);
5761 }
5763 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5764 }
5766 static void
5767 lpetool_open_lpe_dialog (GtkToggleAction *act, gpointer data) {
5768 SPDesktop *desktop = static_cast<SPDesktop *>(data);
5770 if (tools_isactive(desktop, TOOLS_LPETOOL)) {
5771 sp_action_perform(Inkscape::Verb::get(SP_VERB_DIALOG_LIVE_PATH_EFFECT)->get_action(desktop), NULL);
5772 }
5773 gtk_toggle_action_set_active(act, false);
5774 }
5776 static void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5777 {
5778 UnitTracker* tracker = new UnitTracker(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
5779 tracker->setActiveUnit(sp_desktop_namedview(desktop)->doc_units);
5780 g_object_set_data(holder, "tracker", tracker);
5781 SPUnit const *unit = tracker->getActiveUnit();
5783 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5784 prefs->setInt("/tools/lpetool/unitid", unit->unit_id);
5786 /** Automatically create a list of LPEs that get added to the toolbar **/
5787 {
5788 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
5790 GtkTreeIter iter;
5792 // the first toggle button represents the state that no subtool is active (remove this when
5793 // this can be modeled by EgeSelectOneAction or some other action)
5794 gtk_list_store_append( model, &iter );
5795 gtk_list_store_set( model, &iter,
5796 0, _("All inactive"),
5797 1, _("No geometric tool is active"),
5798 2, "draw-geometry-inactive",
5799 -1 );
5801 Inkscape::LivePathEffect::EffectType type;
5802 for (int i = 1; i < num_subtools; ++i) { // we start with i = 1 because INVALID_LPE was already added
5803 type = lpesubtools[i].type;
5804 gtk_list_store_append( model, &iter );
5805 gtk_list_store_set( model, &iter,
5806 0, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
5807 1, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
5808 2, lpesubtools[i].icon_name,
5809 -1 );
5810 }
5812 EgeSelectOneAction* act = ege_select_one_action_new( "LPEToolModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
5813 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
5814 g_object_set_data( holder, "lpetool_mode_action", act );
5816 ege_select_one_action_set_appearance( act, "full" );
5817 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
5818 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
5819 ege_select_one_action_set_icon_column( act, 2 );
5820 ege_select_one_action_set_tooltip_column( act, 1 );
5822 gint lpeToolMode = prefs->getInt("/tools/lpetool/mode", 0);
5823 ege_select_one_action_set_active( act, lpeToolMode );
5824 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_mode_changed), holder );
5825 }
5827 /* Show limiting bounding box */
5828 {
5829 InkToggleAction* act = ink_toggle_action_new( "LPEShowBBoxAction",
5830 _("Show limiting bounding box"),
5831 _("Show bounding box (used to cut infinite lines)"),
5832 "show-bounding-box",
5833 Inkscape::ICON_SIZE_DECORATION );
5834 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5835 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_bbox), desktop );
5836 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_bbox", true ) );
5837 }
5839 /* Set limiting bounding box to bbox of current selection */
5840 {
5841 InkToggleAction* act = ink_toggle_action_new( "LPEBBoxFromSelectionAction",
5842 _("Get limiting bounding box from selection"),
5843 _("Set limiting bounding box (used to cut infinite lines) to the bounding box of current selection"),
5844 "draw-geometry-set-bounding-box",
5845 Inkscape::ICON_SIZE_DECORATION );
5846 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5847 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_set_bbox), desktop );
5848 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE );
5849 }
5852 /* Combo box to choose line segment type */
5853 {
5854 GtkListStore* model = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
5855 EgeSelectOneAction* act = ege_select_one_action_new ("LPELineSegmentAction", "" , (_("Choose a line segment type")), NULL, GTK_TREE_MODEL(model));
5856 ege_select_one_action_set_appearance (act, "compact");
5857 g_object_set_data (holder, "lpetool_line_segment_action", act );
5859 g_object_set_data(holder, "line_segment_list_blocked", GINT_TO_POINTER(FALSE));
5861 sp_line_segment_build_list (holder);
5863 g_signal_connect(G_OBJECT(act), "changed", G_CALLBACK(sp_lpetool_change_line_segment_type), holder);
5864 gtk_action_set_sensitive( GTK_ACTION(act), FALSE );
5865 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
5866 }
5868 /* Display measuring info for selected items */
5869 {
5870 InkToggleAction* act = ink_toggle_action_new( "LPEMeasuringAction",
5871 _("Display measuring info"),
5872 _("Display measuring info for selected items"),
5873 "draw-geometry-show-measuring-info",
5874 Inkscape::ICON_SIZE_DECORATION );
5875 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5876 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_toggle_show_measuring_info), holder );
5877 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool( "/tools/lpetool/show_measuring_info", true ) );
5878 }
5880 // add the units menu
5881 {
5882 GtkAction* act = tracker->createAction( "LPEToolUnitsAction", _("Units"), ("") );
5883 gtk_action_group_add_action( mainActions, act );
5884 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(lpetool_unit_changed), (GObject*)holder );
5885 g_object_set_data(holder, "lpetool_units_action", act);
5886 gtk_action_set_sensitive(act, prefs->getBool("/tools/lpetool/show_measuring_info", true));
5887 }
5889 /* Open LPE dialog (to adapt parameters numerically) */
5890 {
5891 InkToggleAction* act = ink_toggle_action_new( "LPEOpenLPEDialogAction",
5892 _("Open LPE dialog"),
5893 _("Open LPE dialog (to adapt parameters numerically)"),
5894 "dialog-geometry",
5895 Inkscape::ICON_SIZE_DECORATION );
5896 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5897 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(lpetool_open_lpe_dialog), desktop );
5898 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), FALSE );
5899 }
5901 //watch selection
5902 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
5904 sigc::connection *c_selection_modified =
5905 new sigc::connection (sp_desktop_selection (desktop)->connectModified
5906 (sigc::bind (sigc::ptr_fun (sp_lpetool_toolbox_sel_modified), (GObject*)holder)));
5907 pool->add_connection ("selection-modified", c_selection_modified);
5909 sigc::connection *c_selection_changed =
5910 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
5911 (sigc::bind (sigc::ptr_fun(sp_lpetool_toolbox_sel_changed), (GObject*)holder)));
5912 pool->add_connection ("selection-changed", c_selection_changed);
5913 }
5915 //########################
5916 //## Eraser ##
5917 //########################
5919 static void sp_erc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
5920 {
5921 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5922 prefs->setDouble( "/tools/eraser/width", adj->value );
5923 update_presets_list(tbl);
5924 }
5926 static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
5927 {
5928 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
5929 bool eraserMode = ege_select_one_action_get_active( act ) != 0;
5930 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
5931 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5932 prefs->setBool( "/tools/eraser/mode", eraserMode );
5933 }
5935 // only take action if run by the attr_changed listener
5936 if (!g_object_get_data( tbl, "freeze" )) {
5937 // in turn, prevent listener from responding
5938 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
5940 if ( eraserMode != 0 ) {
5941 } else {
5942 }
5943 // TODO finish implementation
5945 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5946 }
5947 }
5949 static void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5950 {
5951 {
5952 /* Width */
5953 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
5954 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
5955 EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction",
5956 _("Pen Width"), _("Width:"),
5957 _("The width of the eraser pen (relative to the visible canvas area)"),
5958 "/tools/eraser/width", 15,
5959 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-eraser",
5960 1, 100, 1.0, 10.0,
5961 labels, values, G_N_ELEMENTS(labels),
5962 sp_erc_width_value_changed, 1, 0);
5963 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
5964 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5965 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
5966 }
5968 {
5969 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
5971 GtkTreeIter iter;
5972 gtk_list_store_append( model, &iter );
5973 gtk_list_store_set( model, &iter,
5974 0, _("Delete"),
5975 1, _("Delete objects touched by the eraser"),
5976 2, INKSCAPE_ICON_DRAW_ERASER_DELETE_OBJECTS,
5977 -1 );
5979 gtk_list_store_append( model, &iter );
5980 gtk_list_store_set( model, &iter,
5981 0, _("Cut"),
5982 1, _("Cut out from objects"),
5983 2, INKSCAPE_ICON_PATH_DIFFERENCE,
5984 -1 );
5986 EgeSelectOneAction* act = ege_select_one_action_new( "EraserModeAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
5987 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
5988 g_object_set_data( holder, "eraser_mode_action", act );
5990 ege_select_one_action_set_appearance( act, "full" );
5991 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
5992 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
5993 ege_select_one_action_set_icon_column( act, 2 );
5994 ege_select_one_action_set_tooltip_column( act, 1 );
5996 /// @todo Convert to boolean?
5997 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
5998 gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
5999 ege_select_one_action_set_active( act, eraserMode );
6000 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder );
6001 }
6003 }
6005 //########################
6006 //## Text Toolbox ##
6007 //########################
6008 /*
6009 static void
6010 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
6011 {
6012 //Call back for letter sizing spinbutton
6013 }
6015 static void
6016 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
6017 {
6018 //Call back for line height spinbutton
6019 }
6021 static void
6022 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
6023 {
6024 //Call back for horizontal kerning spinbutton
6025 }
6027 static void
6028 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
6029 {
6030 //Call back for vertical kerning spinbutton
6031 }
6033 static void
6034 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
6035 {
6036 //Call back for letter rotation spinbutton
6037 }*/
6039 namespace {
6041 void
6042 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
6043 {
6044 // quit if run by the _changed callbacks
6045 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
6046 return;
6047 }
6049 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
6051 SPStyle *query =
6052 sp_style_new (SP_ACTIVE_DOCUMENT);
6054 int result_family =
6055 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
6057 int result_style =
6058 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
6060 int result_numbers =
6061 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
6063 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
6065 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
6066 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) {
6067 // there are no texts in selection, read from prefs
6069 sp_style_read_from_prefs(query, "/tools/text");
6071 if (g_object_get_data(tbl, "text_style_from_prefs")) {
6072 // do not reset the toolbar style from prefs if we already did it last time
6073 sp_style_unref(query);
6074 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6075 return;
6076 }
6077 g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(TRUE));
6078 } else {
6079 g_object_set_data(tbl, "text_style_from_prefs", GINT_TO_POINTER(FALSE));
6080 }
6082 if (query->text)
6083 {
6084 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
6085 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
6086 gtk_entry_set_text (GTK_ENTRY (entry), "");
6088 } else if (query->text->font_specification.value || query->text->font_family.value) {
6090 Gtk::ComboBoxEntry *combo = (Gtk::ComboBoxEntry *) (g_object_get_data (G_OBJECT (tbl), "family-entry-combo"));
6091 GtkEntry *entry = GTK_ENTRY (g_object_get_data (G_OBJECT (tbl), "family-entry"));
6093 // Get the font that corresponds
6094 Glib::ustring familyName;
6096 font_instance * font = font_factory::Default()->FaceFromStyle(query);
6097 if (font) {
6098 familyName = font_factory::Default()->GetUIFamilyString(font->descr);
6099 font->Unref();
6100 font = NULL;
6101 }
6103 gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
6105 Gtk::TreeIter iter;
6106 try {
6107 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
6108 Glib::RefPtr<Gtk::TreeModel> model = combo->get_model();
6109 iter = model->get_iter(path);
6110 } catch (...) {
6111 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
6112 sp_style_unref(query);
6113 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6114 return;
6115 }
6117 combo->set_active (iter);
6118 }
6120 //Size
6121 {
6122 GtkWidget *cbox = GTK_WIDGET(g_object_get_data(G_OBJECT(tbl), "combo-box-size"));
6123 gchar *const str = g_strdup_printf("%.5g", query->font_size.computed);
6124 gtk_entry_set_text(GTK_ENTRY(GTK_BIN(cbox)->child), str);
6125 g_free(str);
6126 }
6128 //Anchor
6129 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
6130 {
6131 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
6132 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6133 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
6134 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6135 }
6136 else
6137 {
6138 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
6139 {
6140 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
6141 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6142 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
6143 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6144 }
6145 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
6146 {
6147 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
6148 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6149 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
6150 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6151 }
6152 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
6153 {
6154 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
6155 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6156 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
6157 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6158 }
6159 }
6161 //Style
6162 {
6163 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
6165 gboolean active = gtk_toggle_button_get_active (button);
6166 gboolean check = ((query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700) && (query->font_weight.computed != SP_CSS_FONT_WEIGHT_NORMAL) && (query->font_weight.computed != SP_CSS_FONT_WEIGHT_LIGHTER));
6168 if (active != check)
6169 {
6170 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6171 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
6172 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6173 }
6174 }
6176 {
6177 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
6179 gboolean active = gtk_toggle_button_get_active (button);
6180 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
6182 if (active != check)
6183 {
6184 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6185 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
6186 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6187 }
6188 }
6190 //Orientation
6191 //locking both buttons, changing one affect all group (both)
6192 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
6193 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6195 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
6196 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
6198 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
6199 {
6200 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
6201 }
6202 else
6203 {
6204 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
6205 }
6206 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6207 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
6208 }
6210 sp_style_unref(query);
6212 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6213 }
6215 void
6216 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
6217 {
6218 sp_text_toolbox_selection_changed (selection, tbl);
6219 }
6221 void
6222 sp_text_toolbox_subselection_changed (gpointer /*tc*/, GObject *tbl)
6223 {
6224 sp_text_toolbox_selection_changed (NULL, tbl);
6225 }
6227 void
6228 sp_text_toolbox_family_changed (GtkComboBoxEntry *,
6229 GObject *tbl)
6230 {
6231 // quit if run by the _changed callbacks
6232 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
6233 return;
6234 }
6236 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
6238 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6239 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
6240 const gchar* family = gtk_entry_get_text (GTK_ENTRY (entry));
6242 //g_print ("family changed to: %s\n", family);
6244 SPStyle *query =
6245 sp_style_new (SP_ACTIVE_DOCUMENT);
6247 int result_fontspec =
6248 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
6250 SPCSSAttr *css = sp_repr_css_attr_new ();
6252 // First try to get the font spec from the stored value
6253 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
6255 if (fontSpec.empty()) {
6256 // Construct a new font specification if it does not yet exist
6257 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
6258 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
6259 fontFromStyle->Unref();
6260 }
6262 if (!fontSpec.empty()) {
6264 Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
6266 if (!newFontSpec.empty()) {
6268 if (fontSpec != newFontSpec) {
6270 font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
6272 if (font) {
6273 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
6275 // Set all the these just in case they were altered when finding the best
6276 // match for the new family and old style...
6278 gchar c[256];
6280 font->Family(c, 256);
6282 sp_repr_css_set_property (css, "font-family", c);
6284 font->Attribute( "weight", c, 256);
6285 sp_repr_css_set_property (css, "font-weight", c);
6287 font->Attribute("style", c, 256);
6288 sp_repr_css_set_property (css, "font-style", c);
6290 font->Attribute("stretch", c, 256);
6291 sp_repr_css_set_property (css, "font-stretch", c);
6293 font->Attribute("variant", c, 256);
6294 sp_repr_css_set_property (css, "font-variant", c);
6296 font->Unref();
6297 }
6298 }
6300 } else {
6301 // If the old font on selection (or default) was not existing on the system,
6302 // ReplaceFontSpecificationFamily does not work. In that case we fall back to blindly
6303 // setting the family reported by the family chooser.
6305 //g_print ("fallback setting family: %s\n", family);
6306 sp_repr_css_set_property (css, "-inkscape-font-specification", family);
6307 sp_repr_css_set_property (css, "font-family", family);
6308 }
6309 }
6311 // If querying returned nothing, set the default style of the tool (for new texts)
6312 if (result_fontspec == QUERY_STYLE_NOTHING)
6313 {
6314 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6315 prefs->mergeStyle("/tools/text/style", css);
6316 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
6317 }
6318 else
6319 {
6320 sp_desktop_set_style (desktop, css, true, true);
6321 }
6323 sp_style_unref(query);
6325 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
6326 _("Text: Change font family"));
6327 sp_repr_css_attr_unref (css);
6329 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
6331 // unfreeze
6332 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6334 // focus to canvas
6335 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6336 }
6339 void
6340 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
6341 gpointer data)
6342 {
6343 if (g_object_get_data (G_OBJECT (button), "block")) return;
6344 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
6345 int prop = GPOINTER_TO_INT(data);
6347 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6348 SPCSSAttr *css = sp_repr_css_attr_new ();
6350 switch (prop)
6351 {
6352 case 0:
6353 {
6354 sp_repr_css_set_property (css, "text-anchor", "start");
6355 sp_repr_css_set_property (css, "text-align", "start");
6356 break;
6357 }
6358 case 1:
6359 {
6360 sp_repr_css_set_property (css, "text-anchor", "middle");
6361 sp_repr_css_set_property (css, "text-align", "center");
6362 break;
6363 }
6365 case 2:
6366 {
6367 sp_repr_css_set_property (css, "text-anchor", "end");
6368 sp_repr_css_set_property (css, "text-align", "end");
6369 break;
6370 }
6372 case 3:
6373 {
6374 sp_repr_css_set_property (css, "text-anchor", "start");
6375 sp_repr_css_set_property (css, "text-align", "justify");
6376 break;
6377 }
6378 }
6380 SPStyle *query =
6381 sp_style_new (SP_ACTIVE_DOCUMENT);
6382 int result_numbers =
6383 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
6385 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
6386 if (result_numbers == QUERY_STYLE_NOTHING)
6387 {
6388 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6389 prefs->mergeStyle("/tools/text/style", css);
6390 }
6392 sp_style_unref(query);
6394 sp_desktop_set_style (desktop, css, true, true);
6395 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
6396 _("Text: Change alignment"));
6397 sp_repr_css_attr_unref (css);
6399 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6400 }
6402 void
6403 sp_text_toolbox_style_toggled (GtkToggleButton *button,
6404 gpointer data)
6405 {
6406 if (g_object_get_data (G_OBJECT (button), "block")) return;
6408 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6409 SPCSSAttr *css = sp_repr_css_attr_new ();
6410 int prop = GPOINTER_TO_INT(data);
6411 bool active = gtk_toggle_button_get_active (button);
6413 SPStyle *query =
6414 sp_style_new (SP_ACTIVE_DOCUMENT);
6416 int result_fontspec =
6417 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
6419 //int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
6420 //int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
6421 //int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
6423 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
6424 Glib::ustring newFontSpec = "";
6426 if (fontSpec.empty()) {
6427 // Construct a new font specification if it does not yet exist
6428 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
6429 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
6430 fontFromStyle->Unref();
6431 }
6433 bool nochange = true;
6434 switch (prop)
6435 {
6436 case 0:
6437 {
6438 if (!fontSpec.empty()) {
6439 newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
6440 if (!newFontSpec.empty()) {
6441 // Don't even set the bold if the font didn't exist on the system
6442 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
6443 nochange = false;
6444 }
6445 }
6446 // set or reset the button according
6447 if(nochange) {
6448 gboolean check = gtk_toggle_button_get_active (button);
6450 if (active != check)
6451 {
6452 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6453 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active);
6454 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6455 }
6456 }
6458 break;
6459 }
6461 case 1:
6462 {
6463 if (!fontSpec.empty()) {
6464 newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
6465 if (!newFontSpec.empty()) {
6466 // Don't even set the italic if the font didn't exist on the system
6467 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
6468 nochange = false;
6469 }
6470 }
6471 if(nochange) {
6472 gboolean check = gtk_toggle_button_get_active (button);
6474 if (active != check)
6475 {
6476 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
6477 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active);
6478 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
6479 }
6480 }
6481 break;
6482 }
6483 }
6485 if (!newFontSpec.empty()) {
6486 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
6487 }
6489 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
6490 if (result_fontspec == QUERY_STYLE_NOTHING)
6491 {
6492 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6493 prefs->mergeStyle("/tools/text/style", css);
6494 }
6496 sp_style_unref(query);
6498 sp_desktop_set_style (desktop, css, true, true);
6499 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
6500 _("Text: Change font style"));
6501 sp_repr_css_attr_unref (css);
6503 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6504 }
6506 void
6507 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
6508 gpointer data)
6509 {
6510 if (g_object_get_data (G_OBJECT (button), "block")) {
6511 return;
6512 }
6514 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6515 SPCSSAttr *css = sp_repr_css_attr_new ();
6516 int prop = GPOINTER_TO_INT(data);
6518 switch (prop)
6519 {
6520 case 0:
6521 {
6522 sp_repr_css_set_property (css, "writing-mode", "lr");
6523 break;
6524 }
6526 case 1:
6527 {
6528 sp_repr_css_set_property (css, "writing-mode", "tb");
6529 break;
6530 }
6531 }
6533 SPStyle *query =
6534 sp_style_new (SP_ACTIVE_DOCUMENT);
6535 int result_numbers =
6536 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
6538 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
6539 if (result_numbers == QUERY_STYLE_NOTHING)
6540 {
6541 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6542 prefs->mergeStyle("/tools/text/style", css);
6543 }
6545 sp_desktop_set_style (desktop, css, true, true);
6546 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
6547 _("Text: Change orientation"));
6548 sp_repr_css_attr_unref (css);
6550 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6551 }
6553 gboolean
6554 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
6555 {
6556 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6557 if (!desktop) return FALSE;
6559 switch (get_group0_keyval (event)) {
6560 case GDK_KP_Enter: // chosen
6561 case GDK_Return:
6562 // unfreeze and update, which will defocus
6563 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6564 sp_text_toolbox_family_changed (NULL, tbl);
6565 return TRUE; // I consumed the event
6566 break;
6567 case GDK_Escape:
6568 // defocus
6569 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6570 return TRUE; // I consumed the event
6571 break;
6572 }
6573 return FALSE;
6574 }
6576 gboolean
6577 sp_text_toolbox_family_list_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject */*tbl*/)
6578 {
6579 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6580 if (!desktop) return FALSE;
6582 switch (get_group0_keyval (event)) {
6583 case GDK_KP_Enter:
6584 case GDK_Return:
6585 case GDK_Escape: // defocus
6586 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6587 return TRUE; // I consumed the event
6588 break;
6589 case GDK_w:
6590 case GDK_W:
6591 if (event->state & GDK_CONTROL_MASK) {
6592 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6593 return TRUE; // I consumed the event
6594 }
6595 break;
6596 }
6597 return FALSE;
6598 }
6601 void
6602 sp_text_toolbox_size_changed (GtkComboBox *cbox,
6603 GObject *tbl)
6604 {
6605 // quit if run by the _changed callbacks
6606 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
6607 return;
6608 }
6610 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
6612 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6614 // If this is not from selecting a size in the list (in which case get_active will give the
6615 // index of the selected item, otherwise -1) and not from user pressing Enter/Return, do not
6616 // process this event. This fixes GTK's stupid insistence on sending an activate change every
6617 // time any character gets typed or deleted, which made this control nearly unusable in 0.45.
6618 if (gtk_combo_box_get_active (cbox) < 0 && !g_object_get_data (tbl, "enter-pressed")) {
6619 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6620 return;
6621 }
6623 gdouble value = -1;
6624 {
6625 gchar *endptr;
6626 gchar *const text = gtk_combo_box_get_active_text(cbox);
6627 if (text) {
6628 value = g_strtod(text, &endptr);
6629 if (endptr == text) { // Conversion failed, non-numeric input.
6630 value = -1;
6631 }
6632 g_free(text);
6633 }
6634 }
6635 if (value <= 0) {
6636 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6637 return; // could not parse value
6638 }
6640 SPCSSAttr *css = sp_repr_css_attr_new ();
6641 Inkscape::CSSOStringStream osfs;
6642 osfs << value;
6643 sp_repr_css_set_property (css, "font-size", osfs.str().c_str());
6645 SPStyle *query =
6646 sp_style_new (SP_ACTIVE_DOCUMENT);
6647 int result_numbers =
6648 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
6650 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
6651 if (result_numbers == QUERY_STYLE_NOTHING)
6652 {
6653 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6654 prefs->mergeStyle("/tools/text/style", css);
6655 }
6657 sp_style_unref(query);
6659 sp_desktop_set_style (desktop, css, true, true);
6660 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
6661 _("Text: Change font size"));
6662 sp_repr_css_attr_unref (css);
6664 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6666 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6667 }
6669 gboolean
6670 sp_text_toolbox_size_focusout (GtkWidget */*w*/, GdkEventFocus */*event*/, GObject *tbl)
6671 {
6672 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6673 if (!desktop) return FALSE;
6675 if (!g_object_get_data (tbl, "esc-pressed")) {
6676 g_object_set_data (tbl, "enter-pressed", gpointer(1));
6677 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
6678 sp_text_toolbox_size_changed (cbox, tbl);
6679 g_object_set_data (tbl, "enter-pressed", gpointer(0));
6680 }
6681 return FALSE; // I consumed the event
6682 }
6685 gboolean
6686 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
6687 {
6688 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6689 if (!desktop) return FALSE;
6691 switch (get_group0_keyval (event)) {
6692 case GDK_Escape: // defocus
6693 g_object_set_data (tbl, "esc-pressed", gpointer(1));
6694 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6695 g_object_set_data (tbl, "esc-pressed", gpointer(0));
6696 return TRUE; // I consumed the event
6697 break;
6698 case GDK_Return: // defocus
6699 case GDK_KP_Enter:
6700 g_object_set_data (tbl, "enter-pressed", gpointer(1));
6701 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
6702 sp_text_toolbox_size_changed (cbox, tbl);
6703 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6704 g_object_set_data (tbl, "enter-pressed", gpointer(0));
6705 return TRUE; // I consumed the event
6706 break;
6707 }
6708 return FALSE;
6709 }
6711 // While editing font name in the entry, disable family_changed by freezing, otherwise completion
6712 // does not work!
6713 gboolean
6714 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
6715 GdkEventFocus */*event*/,
6716 GObject *tbl)
6717 {
6718 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
6719 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1); // select all
6720 return FALSE;
6721 }
6723 gboolean
6724 sp_text_toolbox_entry_focus_out (GtkWidget *entry,
6725 GdkEventFocus */*event*/,
6726 GObject *tbl)
6727 {
6728 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6729 gtk_entry_select_region (GTK_ENTRY (entry), 0, 0); // deselect
6730 return FALSE;
6731 }
6733 void
6734 cell_data_func (GtkCellLayout */*cell_layout*/,
6735 GtkCellRenderer *cell,
6736 GtkTreeModel *tree_model,
6737 GtkTreeIter *iter,
6738 gpointer /*data*/)
6739 {
6740 gchar *family;
6741 gtk_tree_model_get(tree_model, iter, 0, &family, -1);
6742 gchar *const family_escaped = g_markup_escape_text(family, -1);
6744 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
6745 int show_sample = prefs->getInt("/tools/text/show_sample_in_list", 1);
6746 if (show_sample) {
6748 Glib::ustring sample = prefs->getString("/tools/text/font_sample");
6749 gchar *const sample_escaped = g_markup_escape_text(sample.data(), -1);
6751 std::stringstream markup;
6752 markup << family_escaped << " <span foreground='darkgray' font_family='"
6753 << family_escaped << "'>" << sample_escaped << "</span>";
6754 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
6756 g_free(sample_escaped);
6757 } else {
6758 g_object_set (G_OBJECT (cell), "markup", family_escaped, NULL);
6759 }
6761 g_free(family);
6762 g_free(family_escaped);
6763 }
6765 gboolean text_toolbox_completion_match_selected(GtkEntryCompletion */*widget*/,
6766 GtkTreeModel *model,
6767 GtkTreeIter *iter,
6768 GObject *tbl)
6769 {
6770 // We intercept this signal so as to fire family_changed at once (without it, you'd have to
6771 // press Enter again after choosing a completion)
6772 gchar *family = 0;
6773 gtk_tree_model_get(model, iter, 0, &family, -1);
6775 GtkEntry *entry = GTK_ENTRY (g_object_get_data (G_OBJECT (tbl), "family-entry"));
6776 gtk_entry_set_text (GTK_ENTRY (entry), family);
6778 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6779 sp_text_toolbox_family_changed (NULL, tbl);
6780 return TRUE;
6781 }
6784 static void
6785 cbe_add_completion (GtkComboBoxEntry *cbe, GObject *tbl){
6786 GtkEntry *entry;
6787 GtkEntryCompletion *completion;
6788 GtkTreeModel *model;
6790 entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(cbe)));
6791 completion = gtk_entry_completion_new();
6792 model = gtk_combo_box_get_model(GTK_COMBO_BOX(cbe));
6793 gtk_entry_completion_set_model(completion, model);
6794 gtk_entry_completion_set_text_column(completion, 0);
6795 gtk_entry_completion_set_inline_completion(completion, FALSE);
6796 gtk_entry_completion_set_inline_selection(completion, FALSE);
6797 gtk_entry_completion_set_popup_completion(completion, TRUE);
6798 gtk_entry_set_completion(entry, completion);
6800 g_signal_connect (G_OBJECT (completion), "match-selected", G_CALLBACK (text_toolbox_completion_match_selected), tbl);
6802 g_object_unref(completion);
6803 }
6805 void sp_text_toolbox_family_popnotify(GtkComboBox *widget,
6806 void */*property*/,
6807 GObject *tbl)
6808 {
6809 // while the drop-down is open, we disable font family changing, reenabling it only when it closes
6811 gboolean shown;
6812 g_object_get (G_OBJECT(widget), "popup-shown", &shown, NULL);
6813 if (shown) {
6814 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
6815 //g_print("POP: notify: SHOWN\n");
6816 } else {
6817 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
6819 // stupid GTK doesn't let us attach to events in the drop-down window, so we peek here to
6820 // find out if the drop down was closed by Enter and if so, manually update (only
6821 // necessary on Windows, on Linux it updates itself - what a mess, but we'll manage)
6822 GdkEvent *ev = gtk_get_current_event();
6823 if (ev) {
6824 //g_print ("ev type: %d\n", ev->type);
6825 if (ev->type == GDK_KEY_PRESS) {
6826 switch (get_group0_keyval ((GdkEventKey *) ev)) {
6827 case GDK_KP_Enter: // chosen
6828 case GDK_Return:
6829 {
6830 // make sure the chosen one is inserted into the entry
6831 GtkComboBox *combo = GTK_COMBO_BOX (((Gtk::ComboBox *) (g_object_get_data (tbl, "family-entry-combo")))->gobj());
6832 GtkTreeModel *model = gtk_combo_box_get_model(combo);
6833 GtkTreeIter iter;
6834 gboolean has_active = gtk_combo_box_get_active_iter (combo, &iter);
6835 if (has_active) {
6836 gchar *family;
6837 gtk_tree_model_get(model, &iter, 0, &family, -1);
6838 GtkEntry *entry = GTK_ENTRY (g_object_get_data (G_OBJECT (tbl), "family-entry"));
6839 gtk_entry_set_text (GTK_ENTRY (entry), family);
6840 }
6842 // update
6843 sp_text_toolbox_family_changed (NULL, tbl);
6844 break;
6845 }
6846 }
6847 }
6848 }
6850 // regardless of whether we updated, defocus the widget
6851 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
6852 if (desktop)
6853 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
6854 //g_print("POP: notify: HIDDEN\n");
6855 }
6856 }
6858 GtkWidget*
6859 sp_text_toolbox_new (SPDesktop *desktop)
6860 {
6861 GtkToolbar *tbl = GTK_TOOLBAR(gtk_toolbar_new());
6862 GtkIconSize secondarySize = static_cast<GtkIconSize>(prefToSize("/toolbox/secondary", 1));
6864 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
6865 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
6867 GtkTooltips *tt = gtk_tooltips_new();
6869 ////////////Family
6870 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
6871 Gtk::ComboBoxEntry *font_sel = Gtk::manage(new Gtk::ComboBoxEntry(store));
6873 gtk_rc_parse_string (
6874 "style \"dropdown-as-list-style\"\n"
6875 "{\n"
6876 " GtkComboBox::appears-as-list = 1\n"
6877 "}\n"
6878 "widget \"*.toolbox-fontfamily-list\" style \"dropdown-as-list-style\"");
6879 gtk_widget_set_name(GTK_WIDGET (font_sel->gobj()), "toolbox-fontfamily-list");
6880 gtk_tooltips_set_tip (tt, GTK_WIDGET (font_sel->gobj()), _("Select font family (Alt+X to access)"), "");
6882 g_signal_connect (G_OBJECT (font_sel->gobj()), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
6884 cbe_add_completion(font_sel->gobj(), G_OBJECT(tbl));
6886 gtk_toolbar_append_widget( tbl, (GtkWidget*) font_sel->gobj(), "", "");
6887 g_object_set_data (G_OBJECT (tbl), "family-entry-combo", font_sel);
6889 // expand the field a bit so as to view more of the previews in the drop-down
6890 GtkRequisition req;
6891 gtk_widget_size_request (GTK_WIDGET (font_sel->gobj()), &req);
6892 gtk_widget_set_size_request (GTK_WIDGET (font_sel->gobj()), MIN(req.width + 50, 500), -1);
6894 GtkWidget* entry = (GtkWidget*) font_sel->get_entry()->gobj();
6895 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
6897 g_signal_connect (G_OBJECT (font_sel->gobj()), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
6898 g_signal_connect (G_OBJECT (font_sel->gobj()), "notify::popup-shown",
6899 G_CALLBACK (sp_text_toolbox_family_popnotify), tbl);
6900 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
6901 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
6902 g_signal_connect (G_OBJECT (entry), "focus-out-event", G_CALLBACK (sp_text_toolbox_entry_focus_out), tbl);
6904 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
6905 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
6907 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
6908 gtk_cell_layout_clear( GTK_CELL_LAYOUT(font_sel->gobj()) );
6909 gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(font_sel->gobj()) , cell , TRUE );
6910 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT(font_sel->gobj()), cell, GtkCellLayoutDataFunc (cell_data_func), NULL, NULL);
6912 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, secondarySize);
6913 GtkWidget *box = gtk_event_box_new ();
6914 gtk_container_add (GTK_CONTAINER (box), image);
6915 gtk_toolbar_append_widget( tbl, box, "", "");
6916 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
6917 gtk_tooltips_set_tip (tt, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
6918 gtk_widget_hide (GTK_WIDGET (box));
6919 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
6921 ////////////Size
6922 gchar const *const sizes[] = {
6923 "4", "6", "8", "9", "10", "11", "12", "13", "14",
6924 "16", "18", "20", "22", "24", "28",
6925 "32", "36", "40", "48", "56", "64", "72", "144"
6926 };
6928 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
6929 for (unsigned int i = 0; i < G_N_ELEMENTS(sizes); ++i) {
6930 gtk_combo_box_append_text(GTK_COMBO_BOX(cbox), sizes[i]);
6931 }
6932 gtk_widget_set_size_request (cbox, 80, -1);
6933 gtk_toolbar_append_widget( tbl, cbox, "", "");
6934 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
6935 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
6936 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), tbl);
6937 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "focus-out-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_focusout), tbl);
6939 ////////////Text anchor
6940 GtkWidget *group = gtk_radio_button_new (NULL);
6941 GtkWidget *row = gtk_hbox_new (FALSE, 4);
6942 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
6944 // left
6945 GtkWidget *rbutton = group;
6946 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6947 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, secondarySize));
6948 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6950 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6951 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
6952 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
6953 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
6955 // center
6956 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
6957 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6958 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, secondarySize));
6959 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6961 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6962 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
6963 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
6964 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
6966 // right
6967 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
6968 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6969 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, secondarySize));
6970 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6972 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6973 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
6974 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
6975 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
6977 // fill
6978 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
6979 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6980 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, secondarySize));
6981 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
6983 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
6984 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
6985 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
6986 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
6988 gtk_toolbar_append_widget( tbl, row, "", "");
6990 //spacer
6991 gtk_toolbar_append_widget( tbl, gtk_vseparator_new(), "", "" );
6993 ////////////Text style
6994 row = gtk_hbox_new (FALSE, 4);
6996 // bold
6997 rbutton = gtk_toggle_button_new ();
6998 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
6999 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, secondarySize));
7000 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
7001 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
7003 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
7004 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
7005 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
7007 // italic
7008 rbutton = gtk_toggle_button_new ();
7009 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
7010 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, secondarySize));
7011 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
7012 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
7014 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
7015 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
7016 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
7018 gtk_toolbar_append_widget( tbl, row, "", "");
7020 //spacer
7021 gtk_toolbar_append_widget( tbl, gtk_vseparator_new(), "", "" );
7023 // Text orientation
7024 group = gtk_radio_button_new (NULL);
7025 row = gtk_hbox_new (FALSE, 4);
7026 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
7028 // horizontal
7029 rbutton = group;
7030 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
7031 gtk_container_add (GTK_CONTAINER (rbutton),
7032 sp_icon_new (static_cast<Inkscape::IconSize>(secondarySize), INKSCAPE_ICON_FORMAT_TEXT_DIRECTION_HORIZONTAL));
7033 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
7034 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
7036 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
7037 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
7038 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
7040 // vertical
7041 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
7042 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
7043 gtk_container_add (GTK_CONTAINER (rbutton),
7044 sp_icon_new (static_cast<Inkscape::IconSize>(secondarySize), INKSCAPE_ICON_FORMAT_TEXT_DIRECTION_VERTICAL));
7045 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
7046 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
7048 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
7049 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
7050 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
7051 gtk_toolbar_append_widget( tbl, row, "", "" );
7054 //watch selection
7055 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
7057 sigc::connection *c_selection_changed =
7058 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
7059 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
7060 pool->add_connection ("selection-changed", c_selection_changed);
7062 sigc::connection *c_selection_modified =
7063 new sigc::connection (sp_desktop_selection (desktop)->connectModified
7064 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
7065 pool->add_connection ("selection-modified", c_selection_modified);
7067 sigc::connection *c_subselection_changed =
7068 new sigc::connection (desktop->connectToolSubselectionChanged
7069 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
7070 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
7072 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
7075 gtk_widget_show_all( GTK_WIDGET(tbl) );
7077 return GTK_WIDGET(tbl);
7078 } // end of sp_text_toolbox_new()
7080 }//<unnamed> namespace
7083 //#########################
7084 //## Connector ##
7085 //#########################
7087 static void sp_connector_mode_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
7088 {
7089 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7090 prefs->setBool("/tools/connector/mode",
7091 gtk_toggle_action_get_active( act ));
7092 }
7094 static void sp_connector_path_set_avoid(void)
7095 {
7096 cc_selection_set_avoid(true);
7097 }
7100 static void sp_connector_path_set_ignore(void)
7101 {
7102 cc_selection_set_avoid(false);
7103 }
7105 static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl )
7106 {
7107 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
7108 Inkscape::Selection * selection = sp_desktop_selection(desktop);
7109 SPDocument *doc = sp_desktop_document(desktop);
7111 if (!sp_document_get_undo_sensitive(doc))
7112 {
7113 return;
7114 }
7117 // quit if run by the _changed callbacks
7118 if (g_object_get_data( tbl, "freeze" )) {
7119 return;
7120 }
7122 // in turn, prevent callbacks from responding
7123 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
7125 bool is_orthog = gtk_toggle_action_get_active( act );
7126 gchar orthog_str[] = "orthogonal";
7127 gchar polyline_str[] = "polyline";
7128 gchar *value = is_orthog ? orthog_str : polyline_str ;
7130 bool modmade = false;
7131 GSList *l = (GSList *) selection->itemList();
7132 while (l) {
7133 SPItem *item = (SPItem *) l->data;
7135 if (cc_item_is_connector(item)) {
7136 sp_object_setAttribute(item, "inkscape:connector-type",
7137 value, false);
7138 item->avoidRef->handleSettingChange();
7139 modmade = true;
7140 }
7141 l = l->next;
7142 }
7144 if (!modmade)
7145 {
7146 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7147 prefs->setBool("/tools/connector/orthogonal", is_orthog);
7148 }
7150 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
7151 is_orthog ? _("Set connector type: orthogonal"): _("Set connector type: polyline"));
7153 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
7154 }
7156 static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl)
7157 {
7158 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
7159 Inkscape::Selection * selection = sp_desktop_selection(desktop);
7160 SPDocument *doc = sp_desktop_document(desktop);
7162 if (!sp_document_get_undo_sensitive(doc))
7163 {
7164 return;
7165 }
7168 // quit if run by the _changed callbacks
7169 if (g_object_get_data( tbl, "freeze" )) {
7170 return;
7171 }
7173 // in turn, prevent callbacks from responding
7174 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
7176 gdouble newValue = gtk_adjustment_get_value(adj);
7177 gchar value[G_ASCII_DTOSTR_BUF_SIZE];
7178 g_ascii_dtostr(value, G_ASCII_DTOSTR_BUF_SIZE, newValue);
7180 bool modmade = false;
7181 GSList *l = (GSList *) selection->itemList();
7182 while (l) {
7183 SPItem *item = (SPItem *) l->data;
7185 if (cc_item_is_connector(item)) {
7186 sp_object_setAttribute(item, "inkscape:connector-curvature",
7187 value, false);
7188 item->avoidRef->handleSettingChange();
7189 modmade = true;
7190 }
7191 l = l->next;
7192 }
7194 if (!modmade)
7195 {
7196 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7197 prefs->setDouble(Glib::ustring("/tools/connector/curvature"), newValue);
7198 }
7200 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
7201 _("Change connector curvature"));
7203 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
7204 }
7207 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
7208 {
7209 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
7210 SPDocument *doc = sp_desktop_document(desktop);
7212 if (!sp_document_get_undo_sensitive(doc))
7213 {
7214 return;
7215 }
7217 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
7219 if ( !repr->attribute("inkscape:connector-spacing") &&
7220 ( adj->value == defaultConnSpacing )) {
7221 // Don't need to update the repr if the attribute doesn't
7222 // exist and it is being set to the default value -- as will
7223 // happen at startup.
7224 return;
7225 }
7227 // quit if run by the attr_changed listener
7228 if (g_object_get_data( tbl, "freeze" )) {
7229 return;
7230 }
7232 // in turn, prevent listener from responding
7233 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
7235 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
7236 SP_OBJECT(desktop->namedview)->updateRepr();
7238 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
7239 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
7240 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
7241 Geom::Matrix m = Geom::identity();
7242 avoid_item_move(&m, item);
7243 }
7245 if (items) {
7246 g_slist_free(items);
7247 }
7249 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
7250 _("Change connector spacing"));
7252 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
7253 }
7255 static void sp_connector_graph_layout(void)
7256 {
7257 if (!SP_ACTIVE_DESKTOP) return;
7258 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7260 // hack for clones, see comment in align-and-distribute.cpp
7261 int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
7262 prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
7264 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
7266 prefs->setInt("/options/clonecompensation/value", saved_compensation);
7268 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
7269 }
7271 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
7272 {
7273 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7274 prefs->setBool("/tools/connector/directedlayout",
7275 gtk_toggle_action_get_active( act ));
7276 }
7278 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
7279 {
7280 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7281 prefs->setBool("/tools/connector/avoidoverlaplayout",
7282 gtk_toggle_action_get_active( act ));
7283 }
7286 static void connector_length_changed(GtkAdjustment *adj, GObject* /*tbl*/)
7287 {
7288 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7289 prefs->setDouble("/tools/connector/length", adj->value);
7290 }
7292 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
7293 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
7294 bool /*is_interactive*/, gpointer data)
7295 {
7296 GtkWidget *tbl = GTK_WIDGET(data);
7298 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
7299 return;
7300 }
7301 if (strcmp(name, "inkscape:connector-spacing") == 0)
7302 {
7303 GtkAdjustment *adj = (GtkAdjustment*)
7304 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
7305 gdouble spacing = defaultConnSpacing;
7306 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
7308 gtk_adjustment_set_value(adj, spacing);
7309 gtk_adjustment_value_changed(adj);
7310 }
7312 spinbutton_defocus(GTK_OBJECT(tbl));
7313 }
7315 static void sp_connector_new_connection_point(GtkWidget *, GObject *tbl)
7316 {
7317 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
7318 SPConnectorContext* cc = SP_CONNECTOR_CONTEXT(desktop->event_context);
7320 if (cc->mode == SP_CONNECTOR_CONTEXT_EDITING_MODE)
7321 cc_create_connection_point(cc);
7322 }
7324 static void sp_connector_remove_connection_point(GtkWidget *, GObject *tbl)
7325 {
7326 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
7327 SPConnectorContext* cc = SP_CONNECTOR_CONTEXT(desktop->event_context);
7329 if (cc->mode == SP_CONNECTOR_CONTEXT_EDITING_MODE)
7330 cc_remove_connection_point(cc);
7331 }
7333 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
7334 NULL, /* child_added */
7335 NULL, /* child_removed */
7336 connector_tb_event_attr_changed,
7337 NULL, /* content_changed */
7338 NULL /* order_changed */
7339 };
7341 static void sp_connector_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
7342 {
7343 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "curvature" ) );
7344 GtkToggleAction *act = GTK_TOGGLE_ACTION( g_object_get_data( tbl, "orthogonal" ) );
7345 SPItem *item = selection->singleItem();
7346 if (SP_IS_PATH(item))
7347 {
7348 gdouble curvature = SP_PATH(item)->connEndPair.getCurvature();
7349 bool is_orthog = SP_PATH(item)->connEndPair.isOrthogonal();
7350 gtk_toggle_action_set_active(act, is_orthog);
7351 gtk_adjustment_set_value(adj, curvature);
7352 }
7354 }
7356 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
7357 {
7358 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7359 Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1);
7361 // Editing mode toggle button
7362 {
7363 InkToggleAction* act = ink_toggle_action_new( "ConnectorEditModeAction",
7364 _("EditMode"),
7365 _("Switch between connection point editing and connector drawing mode"),
7366 INKSCAPE_ICON_CONNECTOR_EDIT,
7367 Inkscape::ICON_SIZE_DECORATION );
7368 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
7370 bool tbuttonstate = prefs->getBool("/tools/connector/mode");
7371 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE ));
7372 g_object_set_data( holder, "mode", act );
7373 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_connector_mode_toggled), holder );
7374 }
7377 {
7378 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
7379 _("Avoid"),
7380 _("Make connectors avoid selected objects"),
7381 INKSCAPE_ICON_CONNECTOR_AVOID,
7382 secondarySize );
7383 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
7384 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
7385 }
7387 {
7388 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
7389 _("Ignore"),
7390 _("Make connectors ignore selected objects"),
7391 INKSCAPE_ICON_CONNECTOR_IGNORE,
7392 secondarySize );
7393 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
7394 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
7395 }
7397 // Orthogonal connectors toggle button
7398 {
7399 InkToggleAction* act = ink_toggle_action_new( "ConnectorOrthogonalAction",
7400 _("Orthogonal"),
7401 _("Make connector orthogonal or polyline"),
7402 INKSCAPE_ICON_CONNECTOR_ORTHOGONAL,
7403 Inkscape::ICON_SIZE_DECORATION );
7404 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
7406 bool tbuttonstate = prefs->getBool("/tools/connector/orthogonal");
7407 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE ));
7408 g_object_set_data( holder, "orthogonal", act );
7409 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_connector_orthogonal_toggled), holder );
7410 }
7412 EgeAdjustmentAction* eact = 0;
7413 // Curvature spinbox
7414 eact = create_adjustment_action( "ConnectorCurvatureAction",
7415 _("Connector Curvature"), _("Curvature:"),
7416 _("The amount of connectors curvature"),
7417 "/tools/connector/curvature", defaultConnCurvature,
7418 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-curvature",
7419 0, 100, 1.0, 10.0,
7420 0, 0, 0,
7421 connector_curvature_changed, 1, 0 );
7422 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
7424 // Spacing spinbox
7425 eact = create_adjustment_action( "ConnectorSpacingAction",
7426 _("Connector Spacing"), _("Spacing:"),
7427 _("The amount of space left around objects by auto-routing connectors"),
7428 "/tools/connector/spacing", defaultConnSpacing,
7429 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
7430 0, 100, 1.0, 10.0,
7431 0, 0, 0,
7432 connector_spacing_changed, 1, 0 );
7433 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
7435 // Graph (connector network) layout
7436 {
7437 InkAction* inky = ink_action_new( "ConnectorGraphAction",
7438 _("Graph"),
7439 _("Nicely arrange selected connector network"),
7440 INKSCAPE_ICON_DISTRIBUTE_GRAPH,
7441 secondarySize );
7442 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
7443 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
7444 }
7446 // Default connector length spinbox
7447 eact = create_adjustment_action( "ConnectorLengthAction",
7448 _("Connector Length"), _("Length:"),
7449 _("Ideal length for connectors when layout is applied"),
7450 "/tools/connector/length", 100,
7451 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
7452 10, 1000, 10.0, 100.0,
7453 0, 0, 0,
7454 connector_length_changed, 1, 0 );
7455 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
7458 // Directed edges toggle button
7459 {
7460 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
7461 _("Downwards"),
7462 _("Make connectors with end-markers (arrows) point downwards"),
7463 INKSCAPE_ICON_DISTRIBUTE_GRAPH_DIRECTED,
7464 Inkscape::ICON_SIZE_DECORATION );
7465 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
7467 bool tbuttonstate = prefs->getBool("/tools/connector/directedlayout");
7468 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), ( tbuttonstate ? TRUE : FALSE ));
7470 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
7471 sigc::connection *connection = new sigc::connection(sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_connector_toolbox_selection_changed), (GObject *)holder))
7472 );
7473 }
7475 // Avoid overlaps toggle button
7476 {
7477 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
7478 _("Remove overlaps"),
7479 _("Do not allow overlapping shapes"),
7480 INKSCAPE_ICON_DISTRIBUTE_REMOVE_OVERLAPS,
7481 Inkscape::ICON_SIZE_DECORATION );
7482 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
7484 bool tbuttonstate = prefs->getBool("/tools/connector/avoidoverlaplayout");
7485 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), (tbuttonstate ? TRUE : FALSE ));
7487 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
7488 }
7491 // New connection point button
7492 {
7493 InkAction* inky = ink_action_new( "ConnectorNewConnPointAction",
7494 _("New connection point"),
7495 _("Add a new connection point to the currently selected item"),
7496 INKSCAPE_ICON_CONNECTOR_NEW_CONNPOINT,
7497 secondarySize );
7498 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_new_connection_point), holder );
7499 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
7500 }
7502 // Remove selected connection point button
7504 {
7505 InkAction* inky = ink_action_new( "ConnectorRemoveConnPointAction",
7506 _("Remove connection point"),
7507 _("Remove the currently selected connection point"),
7508 INKSCAPE_ICON_CONNECTOR_REMOVE_CONNPOINT,
7509 secondarySize );
7510 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_remove_connection_point), holder );
7511 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
7512 }
7515 // Code to watch for changes to the connector-spacing attribute in
7516 // the XML.
7517 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
7518 g_assert(repr != NULL);
7520 purge_repr_listener( holder, holder );
7522 if (repr) {
7523 g_object_set_data( holder, "repr", repr );
7524 Inkscape::GC::anchor(repr);
7525 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
7526 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
7527 }
7528 } // end of sp_connector_toolbox_prep()
7531 //#########################
7532 //## Paintbucket ##
7533 //#########################
7535 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
7536 {
7537 gint channels = ege_select_one_action_get_active( act );
7538 flood_channels_set_channels( channels );
7539 }
7541 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
7542 {
7543 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7544 prefs->setInt("/tools/paintbucket/threshold", (gint)adj->value);
7545 }
7547 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
7548 {
7549 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7550 prefs->setBool("/tools/paintbucket/autogap", ege_select_one_action_get_active( act ));
7551 }
7553 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
7554 {
7555 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
7556 SPUnit const *unit = tracker->getActiveUnit();
7557 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7559 prefs->setDouble("/tools/paintbucket/offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
7560 prefs->setString("/tools/paintbucket/offsetunits", sp_unit_get_abbreviation(unit));
7561 }
7563 static void paintbucket_defaults (GtkWidget *, GObject *tbl)
7564 {
7565 // FIXME: make defaults settable via Inkscape Options
7566 struct KeyValue {
7567 char const *key;
7568 double value;
7569 } const key_values[] = {
7570 {"threshold", 15},
7571 {"offset", 0.0}
7572 };
7574 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
7575 KeyValue const &kv = key_values[i];
7576 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(tbl, kv.key));
7577 if ( adj ) {
7578 gtk_adjustment_set_value(adj, kv.value);
7579 }
7580 }
7582 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "channels_action" ) );
7583 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
7584 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data (tbl, "autogap_action" ) );
7585 ege_select_one_action_set_active( autogap_action, 0 );
7586 }
7588 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
7589 {
7590 EgeAdjustmentAction* eact = 0;
7591 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
7593 {
7594 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
7596 GList* items = 0;
7597 gint count = 0;
7598 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
7599 {
7600 GtkTreeIter iter;
7601 gtk_list_store_append( model, &iter );
7602 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
7603 count++;
7604 }
7605 g_list_free( items );
7606 items = 0;
7607 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
7608 g_object_set( act1, "short_label", _("Fill by:"), NULL );
7609 ege_select_one_action_set_appearance( act1, "compact" );
7610 ege_select_one_action_set_active( act1, prefs->getInt("/tools/paintbucket/channels", 0) );
7611 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
7612 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
7613 g_object_set_data( holder, "channels_action", act1 );
7614 }
7616 // Spacing spinbox
7617 {
7618 eact = create_adjustment_action(
7619 "ThresholdAction",
7620 _("Fill Threshold"), _("Threshold:"),
7621 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
7622 "/tools/paintbucket/threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
7623 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
7624 0, 0, 0,
7625 paintbucket_threshold_changed, 1, 0 );
7627 ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
7628 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
7629 }
7631 // Create the units menu.
7632 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
7633 Glib::ustring stored_unit = prefs->getString("/tools/paintbucket/offsetunits");
7634 if (!stored_unit.empty())
7635 tracker->setActiveUnit(sp_unit_get_by_abbreviation(stored_unit.data()));
7636 g_object_set_data( holder, "tracker", tracker );
7637 {
7638 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
7639 gtk_action_group_add_action( mainActions, act );
7640 }
7642 // Offset spinbox
7643 {
7644 eact = create_adjustment_action(
7645 "OffsetAction",
7646 _("Grow/shrink by"), _("Grow/shrink by:"),
7647 _("The amount to grow (positive) or shrink (negative) the created fill path"),
7648 "/tools/paintbucket/offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
7649 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
7650 0, 0, 0,
7651 paintbucket_offset_changed, 1, 2);
7652 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
7654 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
7655 }
7657 /* Auto Gap */
7658 {
7659 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
7661 GList* items = 0;
7662 gint count = 0;
7663 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
7664 {
7665 GtkTreeIter iter;
7666 gtk_list_store_append( model, &iter );
7667 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
7668 count++;
7669 }
7670 g_list_free( items );
7671 items = 0;
7672 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
7673 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
7674 ege_select_one_action_set_appearance( act2, "compact" );
7675 ege_select_one_action_set_active( act2, prefs->getBool("/tools/paintbucket/autogap") );
7676 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
7677 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
7678 g_object_set_data( holder, "autogap_action", act2 );
7679 }
7681 /* Reset */
7682 {
7683 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
7684 _("Defaults"),
7685 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
7686 GTK_STOCK_CLEAR );
7687 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
7688 gtk_action_group_add_action( mainActions, act );
7689 gtk_action_set_sensitive( act, TRUE );
7690 }
7692 }
7694 /*
7695 Local Variables:
7696 mode:c++
7697 c-file-style:"stroustrup"
7698 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
7699 indent-tabs-mode:nil
7700 fill-column:99
7701 End:
7702 */
7703 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :