1 /** \file
2 * Controls bars for some of Inkscape's tools
3 * (for some tools, they are in their own files)
4 */
6 /*
7 *
8 * Authors:
9 * MenTaLguY <mental@rydia.net>
10 * Lauris Kaplinski <lauris@kaplinski.com>
11 * bulia byak <buliabyak@users.sf.net>
12 * Frank Felfe <innerspace@iname.com>
13 * John Cliff <simarilius@yahoo.com>
14 * David Turner <novalis@gnu.org>
15 * Josh Andler <scislac@scislac.com>
16 * Jon A. Cruz <jon@joncruz.org>
17 *
18 * Copyright (C) 2004 David Turner
19 * Copyright (C) 2003 MenTaLguY
20 * Copyright (C) 1999-2006 authors
21 * Copyright (C) 2001-2002 Ximian, Inc.
22 *
23 * Released under GNU GPL, read the file 'COPYING' for more information
24 */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <gtkmm.h>
31 #include <gtk/gtk.h>
32 #include <iostream>
33 #include <sstream>
35 #include "widgets/button.h"
36 #include "widgets/widget-sizes.h"
37 #include "widgets/spw-utilities.h"
38 #include "widgets/spinbutton-events.h"
39 #include "dialogs/text-edit.h"
41 #include "ui/widget/style-swatch.h"
43 #include "prefs-utils.h"
44 #include "verbs.h"
45 #include "sp-namedview.h"
46 #include "desktop.h"
47 #include "desktop-handles.h"
48 #include "xml/repr.h"
49 #include "xml/node-event-vector.h"
50 #include <glibmm/i18n.h>
51 #include "helper/unit-menu.h"
52 #include "helper/units.h"
54 #include "inkscape.h"
55 #include "conn-avoid-ref.h"
58 #include "select-toolbar.h"
59 #include "gradient-toolbar.h"
61 #include "connector-context.h"
62 #include "node-context.h"
63 #include "shape-editor.h"
64 #include "tweak-context.h"
65 #include "sp-rect.h"
66 #include "box3d.h"
67 #include "box3d-context.h"
68 #include "sp-star.h"
69 #include "sp-spiral.h"
70 #include "sp-ellipse.h"
71 #include "sp-text.h"
72 #include "sp-flowtext.h"
73 #include "style.h"
74 #include "selection.h"
75 #include "selection-chemistry.h"
76 #include "document-private.h"
77 #include "desktop-style.h"
78 #include "../libnrtype/font-lister.h"
79 #include "../connection-pool.h"
80 #include "../prefs-utils.h"
81 #include "../inkscape-stock.h"
82 #include "icon.h"
83 #include "graphlayout/graphlayout.h"
85 #include "mod360.h"
87 #include "toolbox.h"
89 #include "flood-context.h"
91 #include "ink-action.h"
92 #include "ege-adjustment-action.h"
93 #include "ege-output-action.h"
94 #include "ege-select-one-action.h"
95 #include "helper/unit-tracker.h"
97 using Inkscape::UnitTracker;
99 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
100 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
102 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
103 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
104 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
105 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
115 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
118 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
121 static struct {
122 gchar const *type_name;
123 gchar const *data_name;
124 sp_verb_t verb;
125 sp_verb_t doubleclick_verb;
126 } const tools[] = {
127 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
128 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
129 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
130 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
131 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
132 // { "SP3DBoxContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
133 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
134 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
135 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
136 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
137 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
138 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
139 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
140 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
141 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
142 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
143 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
144 { NULL, NULL, 0, 0 }
145 };
147 static struct {
148 gchar const *type_name;
149 gchar const *data_name;
150 GtkWidget *(*create_func)(SPDesktop *desktop);
151 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
152 gchar const *ui_name;
153 gint swatch_verb_id;
154 gchar const *swatch_tool;
155 gchar const *swatch_tip;
156 } const aux_toolboxes[] = {
157 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
158 SP_VERB_INVALID, 0, 0},
159 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
160 SP_VERB_INVALID, 0, 0},
161 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
162 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", _("Color/opacity used for color tweaking")},
163 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
164 SP_VERB_INVALID, 0, 0},
165 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
166 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
167 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
168 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
169 { "SP3DBoxContext", "3dbox_toolbox", 0, sp_3dbox_toolbox_prep, "3DBoxToolbar",
170 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
171 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
172 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
173 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
174 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
175 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
176 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
177 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
178 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
179 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
180 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
181 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
182 SP_VERB_INVALID, 0, 0},
183 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
184 SP_VERB_INVALID, 0, 0},
185 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
186 SP_VERB_INVALID, 0, 0},
187 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
188 SP_VERB_INVALID, 0, 0},
189 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
190 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
191 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
192 };
195 static gchar const * ui_descr =
196 "<ui>"
197 " <toolbar name='SelectToolbar'>"
198 " <toolitem action='EditSelectAll' />"
199 " <toolitem action='EditSelectAllInAllLayers' />"
200 " <toolitem action='EditDeselect' />"
201 " <separator />"
202 " <toolitem action='ObjectRotate90CCW' />"
203 " <toolitem action='ObjectRotate90' />"
204 " <toolitem action='ObjectFlipHorizontally' />"
205 " <toolitem action='ObjectFlipVertically' />"
206 " <separator />"
207 " <toolitem action='SelectionToBack' />"
208 " <toolitem action='SelectionLower' />"
209 " <toolitem action='SelectionRaise' />"
210 " <toolitem action='SelectionToFront' />"
211 " <separator />"
212 " <toolitem action='XAction' />"
213 " <toolitem action='YAction' />"
214 " <toolitem action='WidthAction' />"
215 " <toolitem action='LockAction' />"
216 " <toolitem action='HeightAction' />"
217 " <toolitem action='UnitsAction' />"
218 " <separator />"
219 " <toolitem action='transform_affect_label' />"
220 " <toolitem action='transform_stroke' />"
221 " <toolitem action='transform_corners' />"
222 " <toolitem action='transform_gradient' />"
223 " <toolitem action='transform_pattern' />"
224 " </toolbar>"
226 " <toolbar name='NodeToolbar'>"
227 " <toolitem action='NodeInsertAction' />"
228 " <toolitem action='NodeDeleteAction' />"
229 " <separator />"
230 " <toolitem action='NodeJoinAction' />"
231 " <toolitem action='NodeJoinSegmentAction' />"
232 " <toolitem action='NodeDeleteSegmentAction' />"
233 " <toolitem action='NodeBreakAction' />"
234 " <separator />"
235 " <toolitem action='NodeCuspAction' />"
236 " <toolitem action='NodeSmoothAction' />"
237 " <toolitem action='NodeSymmetricAction' />"
238 " <separator />"
239 " <toolitem action='NodeLineAction' />"
240 " <toolitem action='NodeCurveAction' />"
241 " <separator />"
242 " <toolitem action='ObjectToPath' />"
243 " <toolitem action='StrokeToPath' />"
244 " <separator />"
245 " <toolitem action='NodesShowHandlesAction' />"
246 " <separator />"
247 " <toolitem action='EditNextLPEParameterAction' />"
248 " <separator />"
249 " <toolitem action='NodeXAction' />"
250 " <toolitem action='NodeYAction' />"
251 " <toolitem action='NodeUnitsAction' />"
252 " </toolbar>"
254 " <toolbar name='TweakToolbar'>"
255 " <toolitem action='TweakWidthAction' />"
256 " <separator />"
257 " <toolitem action='TweakForceAction' />"
258 " <toolitem action='TweakPressureAction' />"
259 " <separator />"
260 " <toolitem action='TweakModeAction' />"
261 " <separator />"
262 " <toolitem action='TweakFidelityAction' />"
263 " <separator />"
264 " <toolitem action='TweakChannelsLabel' />"
265 " <toolitem action='TweakDoH' />"
266 " <toolitem action='TweakDoS' />"
267 " <toolitem action='TweakDoL' />"
268 " <toolitem action='TweakDoO' />"
269 " </toolbar>"
271 " <toolbar name='ZoomToolbar'>"
272 " <toolitem action='ZoomIn' />"
273 " <toolitem action='ZoomOut' />"
274 " <separator />"
275 " <toolitem action='Zoom1:0' />"
276 " <toolitem action='Zoom1:2' />"
277 " <toolitem action='Zoom2:1' />"
278 " <separator />"
279 " <toolitem action='ZoomSelection' />"
280 " <toolitem action='ZoomDrawing' />"
281 " <toolitem action='ZoomPage' />"
282 " <toolitem action='ZoomPageWidth' />"
283 " <separator />"
284 " <toolitem action='ZoomPrev' />"
285 " <toolitem action='ZoomNext' />"
286 " </toolbar>"
288 " <toolbar name='StarToolbar'>"
289 " <separator />"
290 " <toolitem action='StarStateAction' />"
291 " <separator />"
292 " <toolitem action='FlatAction' />"
293 " <separator />"
294 " <toolitem action='MagnitudeAction' />"
295 " <toolitem action='SpokeAction' />"
296 " <toolitem action='RoundednessAction' />"
297 " <toolitem action='RandomizationAction' />"
298 " <separator />"
299 " <toolitem action='StarResetAction' />"
300 " </toolbar>"
302 " <toolbar name='RectToolbar'>"
303 " <toolitem action='RectStateAction' />"
304 " <toolitem action='RectWidthAction' />"
305 " <toolitem action='RectHeightAction' />"
306 " <toolitem action='RadiusXAction' />"
307 " <toolitem action='RadiusYAction' />"
308 " <toolitem action='RectUnitsAction' />"
309 " <separator />"
310 " <toolitem action='RectResetAction' />"
311 " </toolbar>"
313 " <toolbar name='3DBoxToolbar'>"
314 " <toolitem action='3DBoxPosAngleXAction' />"
315 " <toolitem action='3DBoxVPXAction' />"
316 " <separator />"
317 " <toolitem action='3DBoxPosAngleYAction' />"
318 " <toolitem action='3DBoxVPYAction' />"
319 " <separator />"
320 " <toolitem action='3DBoxPosAngleZAction' />"
321 " <toolitem action='3DBoxVPZAction' />"
322 " <separator />"
323 " </toolbar>"
325 " <toolbar name='SpiralToolbar'>"
326 " <toolitem action='SpiralStateAction' />"
327 " <toolitem action='SpiralRevolutionAction' />"
328 " <toolitem action='SpiralExpansionAction' />"
329 " <toolitem action='SpiralT0Action' />"
330 " <separator />"
331 " <toolitem action='SpiralResetAction' />"
332 " </toolbar>"
334 " <toolbar name='PenToolbar'>"
335 " </toolbar>"
337 " <toolbar name='PencilToolbar'>"
338 " </toolbar>"
340 " <toolbar name='CalligraphyToolbar'>"
341 " <separator />"
342 " <toolitem action='CalligraphyWidthAction' />"
343 " <toolitem action='PressureAction' />"
344 " <toolitem action='TraceAction' />"
345 " <toolitem action='ThinningAction' />"
346 " <separator />"
347 " <toolitem action='AngleAction' />"
348 " <toolitem action='TiltAction' />"
349 " <toolitem action='FixationAction' />"
350 " <separator />"
351 " <toolitem action='CapRoundingAction' />"
352 " <separator />"
353 " <toolitem action='TremorAction' />"
354 " <toolitem action='WiggleAction' />"
355 " <toolitem action='MassAction' />"
356 " <separator />"
357 " <toolitem action='CalligraphyResetAction' />"
358 " </toolbar>"
360 " <toolbar name='ArcToolbar'>"
361 " <toolitem action='ArcStateAction' />"
362 " <separator />"
363 " <toolitem action='ArcStartAction' />"
364 " <toolitem action='ArcEndAction' />"
365 " <separator />"
366 " <toolitem action='ArcOpenAction' />"
367 " <separator />"
368 " <toolitem action='ArcResetAction' />"
369 " <separator />"
370 " </toolbar>"
372 " <toolbar name='PaintbucketToolbar'>"
373 " <toolitem action='ChannelsAction' />"
374 " <separator />"
375 " <toolitem action='ThresholdAction' />"
376 " <separator />"
377 " <toolitem action='OffsetAction' />"
378 " <toolitem action='PaintbucketUnitsAction' />"
379 " <separator />"
380 " <toolitem action='AutoGapAction' />"
381 " <separator />"
382 " <toolitem action='PaintbucketResetAction' />"
383 " </toolbar>"
385 " <toolbar name='DropperToolbar'>"
386 " <toolitem action='DropperPickAlphaAction' />"
387 " <toolitem action='DropperSetAlphaAction' />"
388 " </toolbar>"
390 " <toolbar name='ConnectorToolbar'>"
391 " <toolitem action='ConnectorAvoidAction' />"
392 " <toolitem action='ConnectorIgnoreAction' />"
393 " <toolitem action='ConnectorSpacingAction' />"
394 " <toolitem action='ConnectorGraphAction' />"
395 " <toolitem action='ConnectorLengthAction' />"
396 " <toolitem action='ConnectorDirectedAction' />"
397 " <toolitem action='ConnectorOverlapAction' />"
398 " </toolbar>"
400 "</ui>"
401 ;
403 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
405 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
407 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
408 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
410 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
411 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
413 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
414 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
416 /* Global text entry widgets necessary for update */
417 /* GtkWidget *dropper_rgb_entry,
418 *dropper_opacity_entry ; */
419 // should be made a private member once this is converted to class
421 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
422 connection->disconnect();
423 delete connection;
424 }
426 static void purge_repr_listener( GObject* obj, GObject* tbl )
427 {
428 (void)obj;
429 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
430 if (oldrepr) { // remove old listener
431 sp_repr_remove_listener_by_data(oldrepr, tbl);
432 Inkscape::GC::release(oldrepr);
433 oldrepr = 0;
434 g_object_set_data( tbl, "repr", NULL );
435 }
436 }
438 GtkWidget *
439 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
440 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
441 Inkscape::UI::View::View *view, GtkTooltips *tt)
442 {
443 SPAction *action = verb->get_action(view);
444 if (!action) return NULL;
446 SPAction *doubleclick_action;
447 if (doubleclick_verb)
448 doubleclick_action = doubleclick_verb->get_action(view);
449 else
450 doubleclick_action = NULL;
452 /* fixme: Handle sensitive/unsensitive */
453 /* fixme: Implement sp_button_new_from_action */
454 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
455 gtk_widget_show(b);
456 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
458 return b;
459 }
461 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
462 Inkscape::UI::View::View *view, GtkTooltips *tt)
463 {
464 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
465 }
467 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
468 Inkscape::UI::View::View *view, GtkTooltips *tt)
469 {
470 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
471 }
474 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
475 {
476 SPAction* targetAction = SP_ACTION(user_data);
477 if ( targetAction ) {
478 sp_action_perform( targetAction, NULL );
479 }
480 }
482 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
483 {
484 if ( data ) {
485 GtkAction* act = GTK_ACTION(data);
486 gtk_action_set_sensitive( act, sensitive );
487 }
488 }
490 static SPActionEventVector action_event_vector = {
491 {NULL},
492 NULL,
493 NULL,
494 sp_action_action_set_sensitive,
495 NULL,
496 NULL
497 };
499 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
500 {
501 GtkAction* act = 0;
503 SPAction* targetAction = verb->get_action(view);
504 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
505 act = GTK_ACTION(inky);
506 gtk_action_set_sensitive( act, targetAction->sensitive );
508 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
510 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
511 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
513 return act;
514 }
516 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
517 {
518 Inkscape::UI::View::View *view = desktop;
519 gint verbsToUse[] = {
520 // disabled until we have icons for them:
521 //find
522 //SP_VERB_EDIT_TILE,
523 //SP_VERB_EDIT_UNTILE,
524 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
525 SP_VERB_DIALOG_DISPLAY,
526 SP_VERB_DIALOG_FILL_STROKE,
527 SP_VERB_DIALOG_NAMEDVIEW,
528 SP_VERB_DIALOG_TEXT,
529 SP_VERB_DIALOG_XML_EDITOR,
530 SP_VERB_EDIT_CLONE,
531 SP_VERB_EDIT_COPY,
532 SP_VERB_EDIT_CUT,
533 SP_VERB_EDIT_DUPLICATE,
534 SP_VERB_EDIT_PASTE,
535 SP_VERB_EDIT_REDO,
536 SP_VERB_EDIT_UNDO,
537 SP_VERB_EDIT_UNLINK_CLONE,
538 SP_VERB_FILE_EXPORT,
539 SP_VERB_FILE_IMPORT,
540 SP_VERB_FILE_NEW,
541 SP_VERB_FILE_OPEN,
542 SP_VERB_FILE_PRINT,
543 SP_VERB_FILE_SAVE,
544 SP_VERB_OBJECT_TO_CURVE,
545 SP_VERB_SELECTION_GROUP,
546 SP_VERB_SELECTION_OUTLINE,
547 SP_VERB_SELECTION_UNGROUP,
548 SP_VERB_ZOOM_1_1,
549 SP_VERB_ZOOM_1_2,
550 SP_VERB_ZOOM_2_1,
551 SP_VERB_ZOOM_DRAWING,
552 SP_VERB_ZOOM_IN,
553 SP_VERB_ZOOM_NEXT,
554 SP_VERB_ZOOM_OUT,
555 SP_VERB_ZOOM_PAGE,
556 SP_VERB_ZOOM_PAGE_WIDTH,
557 SP_VERB_ZOOM_PREV,
558 SP_VERB_ZOOM_SELECTION,
559 };
561 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
562 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
564 static std::map<SPDesktop*, GtkActionGroup*> groups;
565 GtkActionGroup* mainActions = 0;
566 if ( groups.find(desktop) != groups.end() ) {
567 mainActions = groups[desktop];
568 }
570 if ( !mainActions ) {
571 mainActions = gtk_action_group_new("main");
572 groups[desktop] = mainActions;
573 }
575 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
576 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
577 if ( verb ) {
578 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
579 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
580 gtk_action_group_add_action( mainActions, act );
581 }
582 }
583 }
585 return mainActions;
586 }
589 GtkWidget *
590 sp_tool_toolbox_new()
591 {
592 GtkTooltips *tt = gtk_tooltips_new();
593 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
595 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
596 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
598 gtk_widget_set_sensitive(tb, FALSE);
600 GtkWidget *hb = gtk_handle_box_new();
601 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
602 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
603 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
605 gtk_container_add(GTK_CONTAINER(hb), tb);
606 gtk_widget_show(GTK_WIDGET(tb));
608 sigc::connection* conn = new sigc::connection;
609 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
611 return hb;
612 }
614 static void
615 aux_toolbox_attached(GtkHandleBox */*toolbox*/, GtkWidget *child)
616 {
617 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
618 gtk_widget_queue_resize(child);
619 }
621 static void
622 aux_toolbox_detached(GtkHandleBox */*toolbox*/, GtkWidget *child)
623 {
624 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
625 gtk_widget_queue_resize(child);
626 }
628 GtkWidget *
629 sp_aux_toolbox_new()
630 {
631 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
633 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
634 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
635 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
636 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
637 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
639 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
640 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
642 gtk_widget_set_sensitive(tb, FALSE);
644 GtkWidget *hb = gtk_handle_box_new();
645 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
646 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
647 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
649 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
650 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
652 gtk_container_add(GTK_CONTAINER(hb), tb);
653 gtk_widget_show(GTK_WIDGET(tb));
655 sigc::connection* conn = new sigc::connection;
656 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
658 return hb;
659 }
661 //####################################
662 //# Commands Bar
663 //####################################
665 GtkWidget *
666 sp_commands_toolbox_new()
667 {
668 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
670 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
671 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
672 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
673 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
674 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
676 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
677 gtk_widget_set_sensitive(tb, FALSE);
679 GtkWidget *hb = gtk_handle_box_new();
680 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
681 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
682 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
684 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
685 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
687 gtk_container_add(GTK_CONTAINER(hb), tb);
688 gtk_widget_show(GTK_WIDGET(tb));
690 sigc::connection* conn = new sigc::connection;
691 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
693 return hb;
694 }
696 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
697 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
698 gchar const *path, gchar const *data, gdouble def,
699 GtkWidget *focusTarget,
700 GtkWidget *us,
701 GObject *dataKludge,
702 gboolean altx, gchar const *altx_mark,
703 gdouble lower, gdouble upper, gdouble step, gdouble page,
704 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
705 void (*callback)(GtkAdjustment *, GObject *),
706 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
707 {
708 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
709 lower, upper, step, page, page ) );
710 if (us) {
711 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
712 }
714 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
716 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
717 if ( shortLabel ) {
718 g_object_set( act, "short_label", shortLabel, NULL );
719 }
721 if ( (descrCount > 0) && descrLabels && descrValues ) {
722 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
723 }
725 if ( focusTarget ) {
726 ege_adjustment_action_set_focuswidget( act, focusTarget );
727 }
729 if ( altx && altx_mark ) {
730 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
731 }
733 if ( dataKludge ) {
734 g_object_set_data( dataKludge, data, adj );
735 }
737 // Using a cast just to make sure we pass in the right kind of function pointer
738 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
740 return act;
741 }
744 //####################################
745 //# node editing callbacks
746 //####################################
748 /**
749 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
750 */
751 static ShapeEditor *get_current_shape_editor()
752 {
753 if (!SP_ACTIVE_DESKTOP) {
754 return NULL;
755 }
757 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
759 if (!SP_IS_NODE_CONTEXT(event_context)) {
760 return NULL;
761 }
763 return SP_NODE_CONTEXT(event_context)->shape_editor;
764 }
767 void
768 sp_node_path_edit_add(void)
769 {
770 ShapeEditor *shape_editor = get_current_shape_editor();
771 if (shape_editor) shape_editor->add_node();
772 }
774 void
775 sp_node_path_edit_delete(void)
776 {
777 ShapeEditor *shape_editor = get_current_shape_editor();
778 if (shape_editor) shape_editor->delete_nodes();
779 }
781 void
782 sp_node_path_edit_delete_segment(void)
783 {
784 ShapeEditor *shape_editor = get_current_shape_editor();
785 if (shape_editor) shape_editor->delete_segment();
786 }
788 void
789 sp_node_path_edit_break(void)
790 {
791 ShapeEditor *shape_editor = get_current_shape_editor();
792 if (shape_editor) shape_editor->break_at_nodes();
793 }
795 void
796 sp_node_path_edit_join(void)
797 {
798 ShapeEditor *shape_editor = get_current_shape_editor();
799 if (shape_editor) shape_editor->join_nodes();
800 }
802 void
803 sp_node_path_edit_join_segment(void)
804 {
805 ShapeEditor *shape_editor = get_current_shape_editor();
806 if (shape_editor) shape_editor->join_segments();
807 }
809 void
810 sp_node_path_edit_toline(void)
811 {
812 ShapeEditor *shape_editor = get_current_shape_editor();
813 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
814 }
816 void
817 sp_node_path_edit_tocurve(void)
818 {
819 ShapeEditor *shape_editor = get_current_shape_editor();
820 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
821 }
823 void
824 sp_node_path_edit_cusp(void)
825 {
826 ShapeEditor *shape_editor = get_current_shape_editor();
827 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
828 }
830 void
831 sp_node_path_edit_smooth(void)
832 {
833 ShapeEditor *shape_editor = get_current_shape_editor();
834 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
835 }
837 void
838 sp_node_path_edit_symmetrical(void)
839 {
840 ShapeEditor *shape_editor = get_current_shape_editor();
841 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
842 }
844 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
845 bool show = gtk_toggle_action_get_active( act );
846 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
847 ShapeEditor *shape_editor = get_current_shape_editor();
848 if (shape_editor) shape_editor->show_handles(show);
849 }
851 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
852 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
853 }
855 /* is called when the node selection is modified */
856 static void
857 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
858 {
859 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
860 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
861 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
862 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
864 // quit if run by the attr_changed listener
865 if (g_object_get_data( tbl, "freeze" )) {
866 return;
867 }
869 // in turn, prevent listener from responding
870 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
872 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
873 SPUnit const *unit = tracker->getActiveUnit();
875 ShapeEditor *shape_editor = get_current_shape_editor();
876 if (shape_editor && shape_editor->has_nodepath()) {
877 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
878 int n_selected = 0;
879 if (nodepath) {
880 n_selected = nodepath->numSelected();
881 }
883 if (n_selected == 0) {
884 gtk_action_set_sensitive(xact, FALSE);
885 gtk_action_set_sensitive(yact, FALSE);
886 } else {
887 gtk_action_set_sensitive(xact, TRUE);
888 gtk_action_set_sensitive(yact, TRUE);
889 NR::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
890 NR::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
892 if (n_selected == 1) {
893 NR::Point sel_node = nodepath->singleSelectedCoords();
894 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
895 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[NR::X], *unit));
896 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[NR::Y], *unit));
897 }
898 } else {
899 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
900 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
901 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
902 /* Note: Currently x and y will always have a value, even if the coordinates of the
903 selected nodes don't coincide (in this case we use the coordinates of the center
904 of the bounding box). So the entries are never set to zero. */
905 // FIXME: Maybe we should clear the entry if several nodes are selected
906 // instead of providing a kind of average value
907 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
908 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
909 }
910 }
911 }
912 } else {
913 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
914 gtk_action_set_sensitive(xact, FALSE);
915 gtk_action_set_sensitive(yact, FALSE);
916 }
918 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
919 }
921 static void
922 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
923 {
924 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
926 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
927 SPUnit const *unit = tracker->getActiveUnit();
929 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
930 prefs_set_double_attribute("tools.nodes", value_name, sp_units_get_pixels(adj->value, *unit));
931 }
933 // quit if run by the attr_changed listener
934 if (g_object_get_data( tbl, "freeze" )) {
935 return;
936 }
938 // in turn, prevent listener from responding
939 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
941 ShapeEditor *shape_editor = get_current_shape_editor();
942 if (shape_editor && shape_editor->has_nodepath()) {
943 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
944 if (!strcmp(value_name, "x")) {
945 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::X);
946 }
947 if (!strcmp(value_name, "y")) {
948 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::Y);
949 }
950 }
952 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
953 }
955 static void
956 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
957 {
958 sp_node_path_value_changed(adj, tbl, "x");
959 }
961 static void
962 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
963 {
964 sp_node_path_value_changed(adj, tbl, "y");
965 }
967 //################################
968 //## Node Editing Toolbox ##
969 //################################
971 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
972 {
973 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
974 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
975 g_object_set_data( holder, "tracker", tracker );
977 {
978 InkAction* inky = ink_action_new( "NodeInsertAction",
979 _("Insert node"),
980 _("Insert new nodes into selected segments"),
981 "node_insert",
982 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
983 g_object_set( inky, "short_label", _("Insert"), NULL );
984 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
985 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
986 }
988 {
989 InkAction* inky = ink_action_new( "NodeDeleteAction",
990 _("Delete node"),
991 _("Delete selected nodes"),
992 "node_delete",
993 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
994 g_object_set( inky, "short_label", _("Delete"), NULL );
995 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
996 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
997 }
999 {
1000 InkAction* inky = ink_action_new( "NodeJoinAction",
1001 _("Join endnodes"),
1002 _("Join selected endnodes"),
1003 "node_join",
1004 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1005 g_object_set( inky, "short_label", _("Join"), NULL );
1006 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1007 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1008 }
1010 {
1011 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1012 _("Join Segment"),
1013 _("Join selected endnodes with a new segment"),
1014 "node_join_segment",
1015 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1016 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1017 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1018 }
1020 {
1021 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1022 _("Delete Segment"),
1023 _("Split path between two non-endpoint nodes"),
1024 "node_delete_segment",
1025 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1026 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1027 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1028 }
1030 {
1031 InkAction* inky = ink_action_new( "NodeBreakAction",
1032 _("Node Break"),
1033 _("Break path at selected nodes"),
1034 "node_break",
1035 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1036 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1037 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1038 }
1040 {
1041 InkAction* inky = ink_action_new( "NodeCuspAction",
1042 _("Node Cusp"),
1043 _("Make selected nodes corner"),
1044 "node_cusp",
1045 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1046 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1047 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1048 }
1050 {
1051 InkAction* inky = ink_action_new( "NodeSmoothAction",
1052 _("Node Smooth"),
1053 _("Make selected nodes smooth"),
1054 "node_smooth",
1055 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1056 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1057 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1058 }
1060 {
1061 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1062 _("Node Symmetric"),
1063 _("Make selected nodes symmetric"),
1064 "node_symmetric",
1065 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1066 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1067 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1068 }
1070 {
1071 InkAction* inky = ink_action_new( "NodeLineAction",
1072 _("Node Line"),
1073 _("Make selected segments lines"),
1074 "node_line",
1075 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1076 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1077 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1078 }
1080 {
1081 InkAction* inky = ink_action_new( "NodeCurveAction",
1082 _("Node Curve"),
1083 _("Make selected segments curves"),
1084 "node_curve",
1085 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1086 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1087 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1088 }
1090 {
1091 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1092 _("Show Handles"),
1093 _("Show the Bezier handles of selected nodes"),
1094 "nodes_show_handles",
1095 Inkscape::ICON_SIZE_DECORATION );
1096 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1097 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1098 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1099 }
1101 {
1102 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1103 _("Next Path Effect Parameter"),
1104 _("Show next Path Effect parameter for editing"),
1105 "edit_next_parameter",
1106 Inkscape::ICON_SIZE_DECORATION );
1107 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1108 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1109 }
1111 /* X coord of selected node(s) */
1112 {
1113 EgeAdjustmentAction* eact = 0;
1114 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1115 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1116 eact = create_adjustment_action( "NodeXAction",
1117 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1118 "tools.nodes", "Xcoord", 0,
1119 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1120 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1121 labels, values, G_N_ELEMENTS(labels),
1122 sp_node_path_x_value_changed );
1123 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1124 g_object_set_data( holder, "nodes_x_action", eact );
1125 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1126 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1127 }
1129 /* Y coord of selected node(s) */
1130 {
1131 EgeAdjustmentAction* eact = 0;
1132 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1133 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1134 eact = create_adjustment_action( "NodeYAction",
1135 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1136 "tools.nodes", "Ycoord", 0,
1137 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1138 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1139 labels, values, G_N_ELEMENTS(labels),
1140 sp_node_path_y_value_changed );
1141 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1142 g_object_set_data( holder, "nodes_y_action", eact );
1143 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1144 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1145 }
1147 // add the units menu
1148 {
1149 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1150 gtk_action_group_add_action( mainActions, act );
1151 }
1153 sigc::connection *connection = new sigc::connection (
1154 desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(sp_node_toolbox_coord_changed), (GObject *)holder))
1155 );
1157 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1158 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1159 } // end of sp_node_toolbox_prep()
1162 //########################
1163 //## Zoom Toolbox ##
1164 //########################
1166 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1167 {
1168 // no custom GtkAction setup needed
1169 } // end of sp_zoom_toolbox_prep()
1171 void
1172 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1173 {
1174 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_tool_toolbox, update_tool_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
1175 }
1178 void
1179 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1180 {
1181 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_aux_toolbox, update_aux_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
1182 }
1184 void
1185 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1186 {
1187 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_commands_toolbox, update_commands_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
1188 }
1190 static void
1191 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1192 {
1193 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1194 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1196 if (old_desktop) {
1197 GList *children, *iter;
1199 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1200 for ( iter = children ; iter ; iter = iter->next ) {
1201 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1202 }
1203 g_list_free(children);
1204 }
1206 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1208 if (desktop) {
1209 gtk_widget_set_sensitive(toolbox, TRUE);
1210 setup_func(toolbox, desktop);
1211 update_func(desktop, desktop->event_context, toolbox);
1212 *conn = desktop->connectEventContextChanged
1213 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1214 } else {
1215 gtk_widget_set_sensitive(toolbox, FALSE);
1216 }
1218 } // end of toolbox_set_desktop()
1221 static void
1222 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1223 {
1224 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
1225 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
1226 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
1227 // "toolbox.tools" was not set. Fallback to older value
1228 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
1230 // Copy the setting forwards
1231 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
1232 }
1233 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1235 for (int i = 0 ; tools[i].type_name ; i++ ) {
1236 GtkWidget *button =
1237 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
1238 SP_BUTTON_TYPE_TOGGLE,
1239 Inkscape::Verb::get(tools[i].verb),
1240 Inkscape::Verb::get(tools[i].doubleclick_verb),
1241 desktop,
1242 tooltips );
1244 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1245 (gpointer)button );
1246 }
1247 }
1250 static void
1251 update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
1252 {
1253 gchar const *const tname = ( eventcontext
1254 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1255 : NULL );
1256 for (int i = 0 ; tools[i].type_name ; i++ ) {
1257 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1258 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1259 }
1260 }
1262 static void
1263 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1264 {
1265 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1266 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1267 GtkUIManager* mgr = gtk_ui_manager_new();
1268 GError* errVal = 0;
1269 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1270 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1272 std::map<std::string, GtkWidget*> dataHolders;
1274 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1275 if ( aux_toolboxes[i].prep_func ) {
1276 // converted to GtkActions and UIManager
1278 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1279 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1280 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1281 dataHolders[aux_toolboxes[i].type_name] = kludge;
1282 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1283 } else {
1285 GtkWidget *sub_toolbox = 0;
1286 if (aux_toolboxes[i].create_func == NULL)
1287 sub_toolbox = sp_empty_toolbox_new(desktop);
1288 else {
1289 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1290 }
1292 gtk_size_group_add_widget( grouper, sub_toolbox );
1294 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1295 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1297 }
1298 }
1300 // Second pass to create toolbars *after* all GtkActions are created
1301 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1302 if ( aux_toolboxes[i].prep_func ) {
1303 // converted to GtkActions and UIManager
1305 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1307 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1308 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1310 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1311 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1312 g_free( tmp );
1313 tmp = 0;
1315 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1316 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1317 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1318 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1319 }
1320 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1323 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1325 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1326 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1327 swatch->setDesktop( desktop );
1328 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1329 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1330 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1331 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 );
1332 }
1334 gtk_widget_show_all( holder );
1335 sp_set_font_size_smaller( holder );
1337 gtk_size_group_add_widget( grouper, holder );
1339 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1340 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1341 }
1342 }
1344 g_object_unref( G_OBJECT(grouper) );
1345 }
1347 static void
1348 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1349 {
1350 gchar const *tname = ( eventcontext
1351 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1352 : NULL );
1353 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1354 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1355 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1356 gtk_widget_show_all(sub_toolbox);
1357 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1358 } else {
1359 gtk_widget_hide(sub_toolbox);
1360 }
1361 }
1362 }
1364 static void
1365 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1366 {
1367 gchar const * descr =
1368 "<ui>"
1369 " <toolbar name='CommandsToolbar'>"
1370 " <toolitem action='FileNew' />"
1371 " <toolitem action='FileOpen' />"
1372 " <toolitem action='FileSave' />"
1373 " <toolitem action='FilePrint' />"
1374 " <separator />"
1375 " <toolitem action='FileImport' />"
1376 " <toolitem action='FileExport' />"
1377 " <separator />"
1378 " <toolitem action='EditUndo' />"
1379 " <toolitem action='EditRedo' />"
1380 " <separator />"
1381 " <toolitem action='EditCopy' />"
1382 " <toolitem action='EditCut' />"
1383 " <toolitem action='EditPaste' />"
1384 " <separator />"
1385 " <toolitem action='ZoomSelection' />"
1386 " <toolitem action='ZoomDrawing' />"
1387 " <toolitem action='ZoomPage' />"
1388 " <separator />"
1389 " <toolitem action='EditDuplicate' />"
1390 " <toolitem action='EditClone' />"
1391 " <toolitem action='EditUnlinkClone' />"
1392 " <separator />"
1393 " <toolitem action='SelectionGroup' />"
1394 " <toolitem action='SelectionUnGroup' />"
1395 " <separator />"
1396 " <toolitem action='DialogFillStroke' />"
1397 " <toolitem action='DialogText' />"
1398 " <toolitem action='DialogXMLEditor' />"
1399 " <toolitem action='DialogAlignDistribute' />"
1400 " <separator />"
1401 " <toolitem action='DialogPreferences' />"
1402 " <toolitem action='DialogDocumentProperties' />"
1403 " </toolbar>"
1404 "</ui>";
1405 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1408 GtkUIManager* mgr = gtk_ui_manager_new();
1409 GError* errVal = 0;
1411 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1412 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1414 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1415 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1416 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1417 }
1418 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1419 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1420 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1423 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1424 }
1426 static void
1427 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1428 {
1429 }
1431 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1432 {
1433 gtk_widget_show(toolbox_toplevel);
1434 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1436 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1437 if (!shown_toolbox) {
1438 return;
1439 }
1440 gtk_widget_show(toolbox);
1442 // need to show the spacer, or the padding will be off
1443 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1444 gtk_widget_show(spacer);
1446 gtk_widget_show_all(shown_toolbox);
1447 }
1449 void
1450 aux_toolbox_space(GtkWidget *tb, gint space)
1451 {
1452 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1453 }
1455 static GtkWidget *
1456 sp_empty_toolbox_new(SPDesktop *desktop)
1457 {
1458 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1459 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1460 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1462 gtk_widget_show_all(tbl);
1463 sp_set_font_size_smaller (tbl);
1465 return tbl;
1466 }
1468 // helper UI functions
1470 GtkWidget *
1471 sp_tb_spinbutton(
1472 gchar *label, gchar const *tooltip,
1473 gchar const *path, gchar const *data, gdouble def,
1474 GtkWidget *us,
1475 GtkWidget *tbl,
1476 gboolean altx, gchar const *altx_mark,
1477 gdouble lower, gdouble upper, gdouble step, gdouble page,
1478 void (*callback)(GtkAdjustment *, GtkWidget *),
1479 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1480 {
1481 GtkTooltips *tt = gtk_tooltips_new();
1483 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1485 GtkWidget *l = gtk_label_new(label);
1486 gtk_widget_show(l);
1487 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1488 gtk_container_add(GTK_CONTAINER(hb), l);
1490 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1491 lower, upper, step, page, page);
1492 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1493 if (us)
1494 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1496 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1497 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1498 if (altx)
1499 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1500 gtk_widget_set_size_request(sb,
1501 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1502 AUX_SPINBUTTON_HEIGHT);
1503 gtk_widget_show(sb);
1504 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1505 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1506 gtk_container_add(GTK_CONTAINER(hb), sb);
1507 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1509 return hb;
1510 }
1512 #define MODE_LABEL_WIDTH 70
1514 //########################
1515 //## Star ##
1516 //########################
1518 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1519 {
1520 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1522 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1523 // do not remember prefs if this call is initiated by an undo change, because undoing object
1524 // creation sets bogus values to its attributes before it is deleted
1525 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1526 }
1528 // quit if run by the attr_changed listener
1529 if (g_object_get_data( dataKludge, "freeze" )) {
1530 return;
1531 }
1533 // in turn, prevent listener from responding
1534 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1536 bool modmade = false;
1538 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1539 GSList const *items = selection->itemList();
1540 for (; items != NULL; items = items->next) {
1541 if (SP_IS_STAR((SPItem *) items->data)) {
1542 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1543 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1544 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1545 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1546 + M_PI / (gint)adj->value));
1547 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1548 modmade = true;
1549 }
1550 }
1551 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1552 _("Star: Change number of corners"));
1554 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1555 }
1557 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1558 {
1559 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1561 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1562 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1563 }
1565 // quit if run by the attr_changed listener
1566 if (g_object_get_data( dataKludge, "freeze" )) {
1567 return;
1568 }
1570 // in turn, prevent listener from responding
1571 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1573 bool modmade = false;
1574 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1575 GSList const *items = selection->itemList();
1576 for (; items != NULL; items = items->next) {
1577 if (SP_IS_STAR((SPItem *) items->data)) {
1578 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1580 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1581 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1582 if (r2 < r1) {
1583 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1584 } else {
1585 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1586 }
1588 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1589 modmade = true;
1590 }
1591 }
1593 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1594 _("Star: Change spoke ratio"));
1596 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1597 }
1599 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1600 {
1601 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1602 bool flat = ege_select_one_action_get_active( act ) == 0;
1604 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1605 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1606 flat ? "true" : "false" );
1607 }
1609 // quit if run by the attr_changed listener
1610 if (g_object_get_data( dataKludge, "freeze" )) {
1611 return;
1612 }
1614 // in turn, prevent listener from responding
1615 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1617 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1618 GSList const *items = selection->itemList();
1619 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1620 bool modmade = false;
1622 if ( prop_action ) {
1623 gtk_action_set_sensitive( prop_action, !flat );
1624 }
1626 for (; items != NULL; items = items->next) {
1627 if (SP_IS_STAR((SPItem *) items->data)) {
1628 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1629 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1630 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1631 modmade = true;
1632 }
1633 }
1635 if (modmade) {
1636 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1637 flat ? _("Make polygon") : _("Make star"));
1638 }
1640 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1641 }
1643 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1644 {
1645 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1647 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1648 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1649 }
1651 // quit if run by the attr_changed listener
1652 if (g_object_get_data( dataKludge, "freeze" )) {
1653 return;
1654 }
1656 // in turn, prevent listener from responding
1657 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1659 bool modmade = false;
1661 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1662 GSList const *items = selection->itemList();
1663 for (; items != NULL; items = items->next) {
1664 if (SP_IS_STAR((SPItem *) items->data)) {
1665 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1666 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1667 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1668 modmade = true;
1669 }
1670 }
1671 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1672 _("Star: Change rounding"));
1674 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1675 }
1677 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1678 {
1679 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1681 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1682 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1683 }
1685 // quit if run by the attr_changed listener
1686 if (g_object_get_data( dataKludge, "freeze" )) {
1687 return;
1688 }
1690 // in turn, prevent listener from responding
1691 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1693 bool modmade = false;
1695 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1696 GSList const *items = selection->itemList();
1697 for (; items != NULL; items = items->next) {
1698 if (SP_IS_STAR((SPItem *) items->data)) {
1699 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1700 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1701 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1702 modmade = true;
1703 }
1704 }
1705 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1706 _("Star: Change randomization"));
1708 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1709 }
1712 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1713 gchar const */*old_value*/, gchar const */*new_value*/,
1714 bool /*is_interactive*/, gpointer data)
1715 {
1716 GtkWidget *tbl = GTK_WIDGET(data);
1718 // quit if run by the _changed callbacks
1719 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1720 return;
1721 }
1723 // in turn, prevent callbacks from responding
1724 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1726 GtkAdjustment *adj = 0;
1728 if (!strcmp(name, "inkscape:randomized")) {
1729 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1730 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1731 } else if (!strcmp(name, "inkscape:rounded")) {
1732 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1733 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1734 } else if (!strcmp(name, "inkscape:flatsided")) {
1735 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1736 char const *flatsides = repr->attribute("inkscape:flatsided");
1737 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1738 if ( flatsides && !strcmp(flatsides,"false") ) {
1739 ege_select_one_action_set_active( flat_action, 1 );
1740 gtk_action_set_sensitive( prop_action, TRUE );
1741 } else {
1742 ege_select_one_action_set_active( flat_action, 0 );
1743 gtk_action_set_sensitive( prop_action, FALSE );
1744 }
1745 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1746 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1747 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1748 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1749 if (r2 < r1) {
1750 gtk_adjustment_set_value(adj, r2/r1);
1751 } else {
1752 gtk_adjustment_set_value(adj, r1/r2);
1753 }
1754 } else if (!strcmp(name, "sodipodi:sides")) {
1755 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1756 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1757 }
1759 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1760 }
1763 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1764 {
1765 NULL, /* child_added */
1766 NULL, /* child_removed */
1767 star_tb_event_attr_changed,
1768 NULL, /* content_changed */
1769 NULL /* order_changed */
1770 };
1773 /**
1774 * \param selection Should not be NULL.
1775 */
1776 static void
1777 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1778 {
1779 int n_selected = 0;
1780 Inkscape::XML::Node *repr = NULL;
1782 purge_repr_listener( tbl, tbl );
1784 for (GSList const *items = selection->itemList();
1785 items != NULL;
1786 items = items->next)
1787 {
1788 if (SP_IS_STAR((SPItem *) items->data)) {
1789 n_selected++;
1790 repr = SP_OBJECT_REPR((SPItem *) items->data);
1791 }
1792 }
1794 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1796 if (n_selected == 0) {
1797 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1798 } else if (n_selected == 1) {
1799 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1801 if (repr) {
1802 g_object_set_data( tbl, "repr", repr );
1803 Inkscape::GC::anchor(repr);
1804 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1805 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1806 }
1807 } else {
1808 // FIXME: implement averaging of all parameters for multiple selected stars
1809 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1810 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1811 }
1812 }
1815 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
1816 {
1817 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1818 // callbacks to lump all the changes for all selected objects in one undo step
1820 GtkAdjustment *adj = 0;
1822 // fixme: make settable in prefs!
1823 gint mag = 5;
1824 gdouble prop = 0.5;
1825 gboolean flat = FALSE;
1826 gdouble randomized = 0;
1827 gdouble rounded = 0;
1829 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1830 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1832 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1833 gtk_action_set_sensitive( sb2, !flat );
1835 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1836 gtk_adjustment_set_value(adj, mag);
1837 gtk_adjustment_value_changed(adj);
1839 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1840 gtk_adjustment_set_value(adj, prop);
1841 gtk_adjustment_value_changed(adj);
1843 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1844 gtk_adjustment_set_value(adj, rounded);
1845 gtk_adjustment_value_changed(adj);
1847 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1848 gtk_adjustment_set_value(adj, randomized);
1849 gtk_adjustment_value_changed(adj);
1850 }
1853 void
1854 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1855 {
1856 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1857 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1858 GtkWidget *l = gtk_label_new(NULL);
1859 gtk_label_set_markup(GTK_LABEL(l), title);
1860 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1861 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1862 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1863 }
1866 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1867 {
1868 {
1869 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1870 ege_output_action_set_use_markup( act, TRUE );
1871 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1872 g_object_set_data( holder, "mode_action", act );
1873 }
1875 {
1876 //EgeAdjustmentAction* calligraphy_angle = 0;
1877 EgeAdjustmentAction* eact = 0;
1878 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1879 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1881 /* Flatsided checkbox */
1882 {
1883 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1885 GtkTreeIter iter;
1886 gtk_list_store_append( model, &iter );
1887 gtk_list_store_set( model, &iter,
1888 0, _("Polygon"),
1889 1, _("Regular polygon (with one handle) instead of a star"),
1890 2, "star_flat",
1891 -1 );
1893 gtk_list_store_append( model, &iter );
1894 gtk_list_store_set( model, &iter,
1895 0, _("Star"),
1896 1, _("Star instead of a regular polygon (with one handle)"),
1897 2, "star_angled",
1898 -1 );
1900 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
1901 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1902 g_object_set_data( holder, "flat_action", act );
1904 ege_select_one_action_set_appearance( act, "full" );
1905 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1906 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1907 ege_select_one_action_set_icon_column( act, 2 );
1908 ege_select_one_action_set_tooltip_column( act, 1 );
1910 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1911 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1912 }
1914 /* Magnitude */
1915 {
1916 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
1917 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
1918 eact = create_adjustment_action( "MagnitudeAction",
1919 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
1920 "tools.shapes.star", "magnitude", 3,
1921 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1922 3, 1024, 1, 5,
1923 labels, values, G_N_ELEMENTS(labels),
1924 sp_stb_magnitude_value_changed,
1925 1.0, 0 );
1926 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1927 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1928 }
1930 /* Spoke ratio */
1931 {
1932 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
1933 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
1934 eact = create_adjustment_action( "SpokeAction",
1935 _("Spoke ratio"), _("Spoke ratio:"),
1936 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1937 // Base radius is the same for the closest handle.
1938 _("Base radius to tip radius ratio"),
1939 "tools.shapes.star", "proportion", 0.5,
1940 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1941 0.01, 1.0, 0.01, 0.1,
1942 labels, values, G_N_ELEMENTS(labels),
1943 sp_stb_proportion_value_changed );
1944 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1945 g_object_set_data( holder, "prop_action", eact );
1946 }
1948 if ( !isFlatSided ) {
1949 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1950 } else {
1951 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1952 }
1954 /* Roundedness */
1955 {
1956 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
1957 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
1958 eact = create_adjustment_action( "RoundednessAction",
1959 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1960 "tools.shapes.star", "rounded", 0.0,
1961 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1962 -10.0, 10.0, 0.01, 0.1,
1963 labels, values, G_N_ELEMENTS(labels),
1964 sp_stb_rounded_value_changed );
1965 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1966 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1967 }
1969 /* Randomization */
1970 {
1971 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
1972 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
1973 eact = create_adjustment_action( "RandomizationAction",
1974 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
1975 "tools.shapes.star", "randomized", 0.0,
1976 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1977 -10.0, 10.0, 0.001, 0.01,
1978 labels, values, G_N_ELEMENTS(labels),
1979 sp_stb_randomized_value_changed, 0.1, 3 );
1980 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1981 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1982 }
1983 }
1985 {
1986 /* Reset */
1987 {
1988 GtkAction* act = gtk_action_new( "StarResetAction",
1989 _("Defaults"),
1990 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1991 GTK_STOCK_CLEAR );
1992 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1993 gtk_action_group_add_action( mainActions, act );
1994 gtk_action_set_sensitive( act, TRUE );
1995 }
1996 }
1998 sigc::connection *connection = new sigc::connection(
1999 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
2000 );
2001 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2002 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2003 }
2006 //########################
2007 //## Rect ##
2008 //########################
2010 static void sp_rtb_sensitivize( GObject *tbl )
2011 {
2012 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
2013 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
2014 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
2016 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
2017 gtk_action_set_sensitive( not_rounded, FALSE );
2018 } else {
2019 gtk_action_set_sensitive( not_rounded, TRUE );
2020 }
2021 }
2024 static void
2025 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
2026 void (*setter)(SPRect *, gdouble))
2027 {
2028 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2030 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2031 SPUnit const *unit = tracker->getActiveUnit();
2033 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2034 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
2035 }
2037 // quit if run by the attr_changed listener
2038 if (g_object_get_data( tbl, "freeze" )) {
2039 return;
2040 }
2042 // in turn, prevent listener from responding
2043 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2045 bool modmade = false;
2046 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2047 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2048 if (SP_IS_RECT(items->data)) {
2049 if (adj->value != 0) {
2050 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2051 } else {
2052 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2053 }
2054 modmade = true;
2055 }
2056 }
2058 sp_rtb_sensitivize( tbl );
2060 if (modmade) {
2061 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2062 _("Change rectangle"));
2063 }
2065 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2066 }
2068 static void
2069 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2070 {
2071 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2072 }
2074 static void
2075 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2076 {
2077 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2078 }
2080 static void
2081 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2082 {
2083 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2084 }
2086 static void
2087 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2088 {
2089 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2090 }
2094 static void
2095 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2096 {
2097 GtkAdjustment *adj = 0;
2099 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2100 gtk_adjustment_set_value(adj, 0.0);
2101 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2102 gtk_adjustment_value_changed(adj);
2104 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2105 gtk_adjustment_set_value(adj, 0.0);
2106 gtk_adjustment_value_changed(adj);
2108 sp_rtb_sensitivize( obj );
2109 }
2111 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2112 gchar const */*old_value*/, gchar const */*new_value*/,
2113 bool /*is_interactive*/, gpointer data)
2114 {
2115 GObject *tbl = G_OBJECT(data);
2117 // quit if run by the _changed callbacks
2118 if (g_object_get_data( tbl, "freeze" )) {
2119 return;
2120 }
2122 // in turn, prevent callbacks from responding
2123 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2125 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2126 SPUnit const *unit = tracker->getActiveUnit();
2128 gpointer item = g_object_get_data( tbl, "item" );
2129 if (item && SP_IS_RECT(item)) {
2130 {
2131 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2132 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2133 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2134 }
2136 {
2137 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2138 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2139 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2140 }
2142 {
2143 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2144 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2145 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2146 }
2148 {
2149 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2150 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2151 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2152 }
2153 }
2155 sp_rtb_sensitivize( tbl );
2157 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2158 }
2161 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2162 NULL, /* child_added */
2163 NULL, /* child_removed */
2164 rect_tb_event_attr_changed,
2165 NULL, /* content_changed */
2166 NULL /* order_changed */
2167 };
2169 /**
2170 * \param selection should not be NULL.
2171 */
2172 static void
2173 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2174 {
2175 int n_selected = 0;
2176 Inkscape::XML::Node *repr = NULL;
2177 SPItem *item = NULL;
2179 if ( g_object_get_data( tbl, "repr" ) ) {
2180 g_object_set_data( tbl, "item", NULL );
2181 }
2182 purge_repr_listener( tbl, tbl );
2184 for (GSList const *items = selection->itemList();
2185 items != NULL;
2186 items = items->next) {
2187 if (SP_IS_RECT((SPItem *) items->data)) {
2188 n_selected++;
2189 item = (SPItem *) items->data;
2190 repr = SP_OBJECT_REPR(item);
2191 }
2192 }
2194 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2196 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2198 if (n_selected == 0) {
2199 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2201 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2202 gtk_action_set_sensitive(w, FALSE);
2203 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2204 gtk_action_set_sensitive(h, FALSE);
2206 } else if (n_selected == 1) {
2207 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2208 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2210 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2211 gtk_action_set_sensitive(w, TRUE);
2212 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2213 gtk_action_set_sensitive(h, TRUE);
2215 if (repr) {
2216 g_object_set_data( tbl, "repr", repr );
2217 g_object_set_data( tbl, "item", item );
2218 Inkscape::GC::anchor(repr);
2219 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2220 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2221 }
2222 } else {
2223 // FIXME: implement averaging of all parameters for multiple selected
2224 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2225 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2226 sp_rtb_sensitivize( tbl );
2227 }
2228 }
2231 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2232 {
2233 EgeAdjustmentAction* eact = 0;
2235 {
2236 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2237 ege_output_action_set_use_markup( act, TRUE );
2238 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2239 g_object_set_data( holder, "mode_action", act );
2240 }
2242 // rx/ry units menu: create
2243 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2244 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2245 // fixme: add % meaning per cent of the width/height
2246 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2247 g_object_set_data( holder, "tracker", tracker );
2249 /* W */
2250 {
2251 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2252 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2253 eact = create_adjustment_action( "RectWidthAction",
2254 _("Width"), _("W:"), _("Width of rectangle"),
2255 "tools.shapes.rect", "width", 0,
2256 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2257 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2258 labels, values, G_N_ELEMENTS(labels),
2259 sp_rtb_width_value_changed );
2260 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2261 g_object_set_data( holder, "width_action", eact );
2262 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2263 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2264 }
2266 /* H */
2267 {
2268 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2269 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2270 eact = create_adjustment_action( "RectHeightAction",
2271 _("Height"), _("H:"), _("Height of rectangle"),
2272 "tools.shapes.rect", "height", 0,
2273 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2274 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2275 labels, values, G_N_ELEMENTS(labels),
2276 sp_rtb_height_value_changed );
2277 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2278 g_object_set_data( holder, "height_action", eact );
2279 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2280 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2281 }
2283 /* rx */
2284 {
2285 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2286 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2287 eact = create_adjustment_action( "RadiusXAction",
2288 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2289 "tools.shapes.rect", "rx", 0,
2290 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2291 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2292 labels, values, G_N_ELEMENTS(labels),
2293 sp_rtb_rx_value_changed);
2294 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2295 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2296 }
2298 /* ry */
2299 {
2300 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2301 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2302 eact = create_adjustment_action( "RadiusYAction",
2303 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2304 "tools.shapes.rect", "ry", 0,
2305 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2306 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2307 labels, values, G_N_ELEMENTS(labels),
2308 sp_rtb_ry_value_changed);
2309 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2310 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2311 }
2313 // add the units menu
2314 {
2315 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2316 gtk_action_group_add_action( mainActions, act );
2317 }
2319 /* Reset */
2320 {
2321 InkAction* inky = ink_action_new( "RectResetAction",
2322 _("Not rounded"),
2323 _("Make corners sharp"),
2324 "squared_corner",
2325 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2326 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2327 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2328 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2329 g_object_set_data( holder, "not_rounded", inky );
2330 }
2332 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2333 sp_rtb_sensitivize( holder );
2335 sigc::connection *connection = new sigc::connection(
2336 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2337 );
2338 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2339 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2340 }
2342 //########################
2343 //## 3D Box ##
2344 //########################
2346 static void sp_3dbox_toggle_vp_changed (GtkToggleAction */*act*/, GObject *dataKludge, Box3D::Axis axis)
2347 {
2348 SPDesktop *desktop = (SPDesktop *) g_object_get_data (dataKludge, "desktop");
2349 SPDocument *document = sp_desktop_document (desktop);
2350 Box3D::Perspective3D *persp = document->current_perspective;
2352 g_return_if_fail (is_single_axis_direction (axis));
2353 g_return_if_fail (persp);
2355 persp->toggle_boxes (axis);
2357 gchar *str;
2358 switch (axis) {
2359 case Box3D::X:
2360 str = g_strdup ("box3d_angle_x_action");
2361 break;
2362 case Box3D::Y:
2363 str = g_strdup ("box3d_angle_y_action");
2364 break;
2365 case Box3D::Z:
2366 str = g_strdup ("box3d_angle_z_action");
2367 break;
2368 default:
2369 return;
2370 }
2371 GtkAction* angle_action = GTK_ACTION (g_object_get_data (dataKludge, str));
2372 if (angle_action) {
2373 gtk_action_set_sensitive (angle_action, !persp->get_vanishing_point (axis)->is_finite() );
2374 }
2376 // FIXME: Given how it is realized in the other tools, this is probably not the right way to do it,
2377 // but without the if construct, we get continuous segfaults. Needs further investigation.
2378 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2379 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
2380 _("3D Box: Change perspective"));
2381 }
2382 }
2384 static void sp_3dbox_toggle_vp_x_changed(GtkToggleAction *act, GObject *dataKludge)
2385 {
2386 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::X);
2387 }
2389 static void sp_3dbox_toggle_vp_y_changed(GtkToggleAction *act, GObject *dataKludge)
2390 {
2391 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Y);
2392 }
2394 static void sp_3dbox_toggle_vp_z_changed(GtkToggleAction *act, GObject *dataKludge)
2395 {
2396 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Z);
2397 }
2399 static void sp_3dbox_vp_angle_changed(GtkAdjustment *adj, GObject *dataKludge, Box3D::Axis axis )
2400 {
2401 SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
2402 Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
2404 if (persp) {
2405 double angle = adj->value * M_PI/180;
2406 persp->set_infinite_direction (axis, NR::Point (cos (angle), sin (angle)));
2408 // FIXME: See comment above; without the if construct we get segfaults during undo.
2409 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2410 sp_document_maybe_done(sp_desktop_document(desktop), "perspectiveangle", SP_VERB_CONTEXT_3DBOX,
2411 _("3D Box: Change perspective"));
2412 }
2413 }
2414 //g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
2415 }
2417 static void sp_3dbox_vpx_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2418 {
2419 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::X);
2420 }
2422 static void sp_3dbox_vpy_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2423 {
2424 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Y);
2425 }
2427 static void sp_3dbox_vpz_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2428 {
2429 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Z);
2430 }
2432 // normalize angle so that it lies in the interval [0,360]
2433 static double sp_3dbox_normalize_angle (double a) {
2434 double angle = a + ((int) (a/360.0))*360;
2435 if (angle < 0) {
2436 angle += 360.0;
2437 }
2438 return angle;
2439 }
2441 static void sp_3dbox_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const *name,
2442 gchar const */*old_value*/, gchar const */*new_value*/,
2443 bool /*is_interactive*/, gpointer data)
2444 {
2445 GtkWidget *tbl = GTK_WIDGET(data);
2447 // FIXME: if we check for "freeze" as in other tools, no action is performed at all ...
2448 /***
2449 // quit if run by the _changed callbacks
2450 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2451 return;
2452 }
2454 // in turn, prevent callbacks from responding
2455 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2456 ***/
2458 if (!strcmp(name, "inkscape:perspective")) {
2459 GtkAdjustment *adj = 0;
2460 double angle;
2461 SPDesktop *desktop = (SPDesktop *) g_object_get_data(G_OBJECT(tbl), "desktop");
2462 Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
2464 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_x"));
2465 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::X)->get_angle());
2466 gtk_adjustment_set_value(adj, angle);
2468 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_y"));
2469 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Y)->get_angle());
2470 gtk_adjustment_set_value(adj, angle);
2472 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_z"));
2473 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Z)->get_angle());
2474 gtk_adjustment_set_value(adj, angle);
2475 }
2476 }
2478 static Inkscape::XML::NodeEventVector sp_3dbox_tb_repr_events =
2479 {
2480 NULL, /* child_added */
2481 NULL, /* child_removed */
2482 sp_3dbox_tb_event_attr_changed,
2483 NULL, /* content_changed */
2484 NULL /* order_changed */
2485 };
2487 /**
2488 * \param selection Should not be NULL.
2489 */
2490 static void
2491 sp_3dbox_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2492 {
2493 Inkscape::XML::Node *repr = NULL;
2494 purge_repr_listener(tbl, tbl);
2496 SPItem *item = selection->singleItem();
2497 if (item) {
2498 repr = SP_OBJECT_REPR(item);
2499 if (repr) {
2500 g_object_set_data(tbl, "repr", repr);
2501 Inkscape::GC::anchor(repr);
2502 sp_repr_add_listener(repr, &sp_3dbox_tb_repr_events, tbl);
2503 sp_repr_synthesize_events(repr, &sp_3dbox_tb_repr_events, tbl);
2504 }
2505 }
2506 }
2508 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2509 {
2510 EgeAdjustmentAction* eact = 0;
2511 SPDocument *document = sp_desktop_document (desktop);
2512 Box3D::Perspective3D *persp = document->current_perspective;
2513 bool toggled = false;
2515 /* angle of VP in X direction */
2516 eact = create_adjustment_action("3DBoxPosAngleXAction",
2517 _("Angle X"), _("Angle X:"), _("Angle of infinite vanishing point in X direction"),
2518 "tools.shapes.3dbox", "dir_vp_x", persp->get_vanishing_point (Box3D::X)->get_angle(),
2519 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2520 0.0, 360.0, 1.0, 10.0,
2521 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2522 sp_3dbox_vpx_angle_changed,
2523 0.1, 1);
2524 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2525 g_object_set_data(holder, "box3d_angle_x_action", eact);
2526 if (!persp->get_vanishing_point (Box3D::X)->is_finite()) {
2527 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2528 } else {
2529 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2530 }
2532 /* toggle VP in X direction */
2533 {
2534 InkToggleAction* act = ink_toggle_action_new("3DBoxVPXAction",
2535 _("Toggle VP in X direction"),
2536 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2537 "toggle_vp_x",
2538 Inkscape::ICON_SIZE_DECORATION);
2539 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2540 if (persp) {
2541 toggled = !persp->get_vanishing_point(Box3D::X)->is_finite();
2542 }
2543 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2544 /* we connect the signal after setting the state to avoid switching the state again */
2545 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_x_changed), holder);
2546 }
2548 /* angle of VP in Y direction */
2549 eact = create_adjustment_action("3DBoxPosAngleYAction",
2550 _("Angle Y"), _("Angle Y:"), _("Angle of infinite vanishing point in Y direction"),
2551 "tools.shapes.3dbox", "dir_vp_y", persp->get_vanishing_point (Box3D::Y)->get_angle(),
2552 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2553 0.0, 360.0, 1.0, 10.0,
2554 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2555 sp_3dbox_vpy_angle_changed,
2556 0.1, 1);
2557 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2558 g_object_set_data(holder, "box3d_angle_y_action", eact);
2559 if (!persp->get_vanishing_point (Box3D::Y)->is_finite()) {
2560 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2561 } else {
2562 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2563 }
2565 /* toggle VP in Y direction */
2566 {
2567 InkToggleAction* act = ink_toggle_action_new("3DBoxVPYAction",
2568 _("Toggle VP in Y direction"),
2569 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2570 "toggle_vp_y",
2571 Inkscape::ICON_SIZE_DECORATION);
2572 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2573 if (persp) {
2574 toggled = !persp->get_vanishing_point(Box3D::Y)->is_finite();
2575 }
2576 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2577 /* we connect the signal after setting the state to avoid switching the state again */
2578 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_y_changed), holder);
2579 }
2581 /* angle of VP in Z direction */
2582 eact = create_adjustment_action("3DBoxPosAngleZAction",
2583 _("Angle Z"), _("Angle Z:"), _("Angle of infinite vanishing point in Z direction"),
2584 "tools.shapes.3dbox", "dir_vp_z", persp->get_vanishing_point (Box3D::Z)->get_angle(),
2585 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2586 0.0, 360.0, 1.0, 10.0,
2587 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2588 sp_3dbox_vpz_angle_changed,
2589 0.1, 1);
2591 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2592 g_object_set_data(holder, "box3d_angle_z_action", eact);
2593 if (!persp->get_vanishing_point (Box3D::Z)->is_finite()) {
2594 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2595 } else {
2596 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2597 }
2599 /* toggle VP in Z direction */
2600 {
2601 InkToggleAction* act = ink_toggle_action_new("3DBoxVPZAction",
2602 _("Toggle VP in Z direction"),
2603 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
2604 "toggle_vp_z",
2605 Inkscape::ICON_SIZE_DECORATION);
2606 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2607 if (persp) {
2608 toggled = !persp->get_vanishing_point(Box3D::Z)->is_finite();
2609 }
2610 /* we connect the signal after setting the state to avoid switching the state again */
2611 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2612 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_z_changed), holder);
2613 }
2615 sigc::connection *connection = new sigc::connection(
2616 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_3dbox_toolbox_selection_changed), (GObject *)holder))
2617 );
2618 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
2619 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
2620 }
2622 //########################
2623 //## Spiral ##
2624 //########################
2626 static void
2627 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2628 {
2629 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2631 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2632 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2633 }
2635 // quit if run by the attr_changed listener
2636 if (g_object_get_data( tbl, "freeze" )) {
2637 return;
2638 }
2640 // in turn, prevent listener from responding
2641 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2643 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2645 bool modmade = false;
2646 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2647 items != NULL;
2648 items = items->next)
2649 {
2650 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2651 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2652 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2653 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2654 modmade = true;
2655 }
2656 }
2658 g_free(namespaced_name);
2660 if (modmade) {
2661 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2662 _("Change spiral"));
2663 }
2665 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2666 }
2668 static void
2669 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2670 {
2671 sp_spl_tb_value_changed(adj, tbl, "revolution");
2672 }
2674 static void
2675 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2676 {
2677 sp_spl_tb_value_changed(adj, tbl, "expansion");
2678 }
2680 static void
2681 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2682 {
2683 sp_spl_tb_value_changed(adj, tbl, "t0");
2684 }
2686 static void
2687 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
2688 {
2689 GtkWidget *tbl = GTK_WIDGET(obj);
2691 GtkAdjustment *adj;
2693 // fixme: make settable
2694 gdouble rev = 5;
2695 gdouble exp = 1.0;
2696 gdouble t0 = 0.0;
2698 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2699 gtk_adjustment_set_value(adj, rev);
2700 gtk_adjustment_value_changed(adj);
2702 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2703 gtk_adjustment_set_value(adj, exp);
2704 gtk_adjustment_value_changed(adj);
2706 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2707 gtk_adjustment_set_value(adj, t0);
2708 gtk_adjustment_value_changed(adj);
2710 spinbutton_defocus(GTK_OBJECT(tbl));
2711 }
2714 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2715 gchar const */*old_value*/, gchar const */*new_value*/,
2716 bool /*is_interactive*/, gpointer data)
2717 {
2718 GtkWidget *tbl = GTK_WIDGET(data);
2720 // quit if run by the _changed callbacks
2721 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2722 return;
2723 }
2725 // in turn, prevent callbacks from responding
2726 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2728 GtkAdjustment *adj;
2729 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2730 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2732 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2733 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2735 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2736 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2738 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2739 }
2742 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2743 NULL, /* child_added */
2744 NULL, /* child_removed */
2745 spiral_tb_event_attr_changed,
2746 NULL, /* content_changed */
2747 NULL /* order_changed */
2748 };
2750 static void
2751 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2752 {
2753 int n_selected = 0;
2754 Inkscape::XML::Node *repr = NULL;
2756 purge_repr_listener( tbl, tbl );
2758 for (GSList const *items = selection->itemList();
2759 items != NULL;
2760 items = items->next)
2761 {
2762 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2763 n_selected++;
2764 repr = SP_OBJECT_REPR((SPItem *) items->data);
2765 }
2766 }
2768 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2770 if (n_selected == 0) {
2771 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2772 } else if (n_selected == 1) {
2773 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2775 if (repr) {
2776 g_object_set_data( tbl, "repr", repr );
2777 Inkscape::GC::anchor(repr);
2778 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2779 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2780 }
2781 } else {
2782 // FIXME: implement averaging of all parameters for multiple selected
2783 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2784 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2785 }
2786 }
2789 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2790 {
2791 EgeAdjustmentAction* eact = 0;
2793 {
2794 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2795 ege_output_action_set_use_markup( act, TRUE );
2796 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2797 g_object_set_data( holder, "mode_action", act );
2798 }
2800 /* Revolution */
2801 {
2802 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
2803 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2804 eact = create_adjustment_action( "SpiralRevolutionAction",
2805 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
2806 "tools.shapes.spiral", "revolution", 3.0,
2807 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2808 0.01, 1024.0, 0.1, 1.0,
2809 labels, values, G_N_ELEMENTS(labels),
2810 sp_spl_tb_revolution_value_changed, 1, 2);
2811 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2812 }
2814 /* Expansion */
2815 {
2816 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
2817 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
2818 eact = create_adjustment_action( "SpiralExpansionAction",
2819 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2820 "tools.shapes.spiral", "expansion", 1.0,
2821 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2822 0.0, 1000.0, 0.01, 1.0,
2823 labels, values, G_N_ELEMENTS(labels),
2824 sp_spl_tb_expansion_value_changed);
2825 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2826 }
2828 /* T0 */
2829 {
2830 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
2831 gdouble values[] = {0, 0.5, 0.9};
2832 eact = create_adjustment_action( "SpiralT0Action",
2833 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2834 "tools.shapes.spiral", "t0", 0.0,
2835 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2836 0.0, 0.999, 0.01, 1.0,
2837 labels, values, G_N_ELEMENTS(labels),
2838 sp_spl_tb_t0_value_changed);
2839 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2840 }
2842 /* Reset */
2843 {
2844 InkAction* inky = ink_action_new( "SpiralResetAction",
2845 _("Defaults"),
2846 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2847 GTK_STOCK_CLEAR,
2848 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2849 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2850 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2851 }
2854 sigc::connection *connection = new sigc::connection(
2855 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2856 );
2857 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2858 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2859 }
2861 //########################
2862 //## Pen/Pencil ##
2863 //########################
2866 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2867 {
2868 // Put stuff here
2869 }
2871 static void sp_pencil_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2872 {
2873 // Put stuff here
2874 }
2876 //########################
2877 //## Tweak ##
2878 //########################
2880 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2881 {
2882 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
2883 }
2885 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2886 {
2887 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
2888 }
2890 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
2891 {
2892 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2893 }
2895 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
2896 {
2897 int mode = ege_select_one_action_get_active( act );
2898 prefs_set_int_attribute("tools.tweak", "mode", mode);
2900 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
2901 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
2902 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
2903 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
2904 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
2905 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
2906 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
2907 if (doh) gtk_action_set_sensitive (doh, TRUE);
2908 if (dos) gtk_action_set_sensitive (dos, TRUE);
2909 if (dol) gtk_action_set_sensitive (dol, TRUE);
2910 if (doo) gtk_action_set_sensitive (doo, TRUE);
2911 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
2912 if (fid) gtk_action_set_sensitive (fid, FALSE);
2913 } else {
2914 if (doh) gtk_action_set_sensitive (doh, FALSE);
2915 if (dos) gtk_action_set_sensitive (dos, FALSE);
2916 if (dol) gtk_action_set_sensitive (dol, FALSE);
2917 if (doo) gtk_action_set_sensitive (doo, FALSE);
2918 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
2919 if (fid) gtk_action_set_sensitive (fid, TRUE);
2920 }
2921 }
2923 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2924 {
2925 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
2926 }
2928 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
2929 bool show = gtk_toggle_action_get_active( act );
2930 prefs_set_int_attribute ("tools.tweak", "doh", show ? 1 : 0);
2931 }
2932 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
2933 bool show = gtk_toggle_action_get_active( act );
2934 prefs_set_int_attribute ("tools.tweak", "dos", show ? 1 : 0);
2935 }
2936 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
2937 bool show = gtk_toggle_action_get_active( act );
2938 prefs_set_int_attribute ("tools.tweak", "dol", show ? 1 : 0);
2939 }
2940 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
2941 bool show = gtk_toggle_action_get_active( act );
2942 prefs_set_int_attribute ("tools.tweak", "doo", show ? 1 : 0);
2943 }
2945 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2946 {
2947 {
2948 /* Width */
2949 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
2950 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2951 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
2952 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
2953 "tools.tweak", "width", 15,
2954 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
2955 1, 100, 1.0, 10.0,
2956 labels, values, G_N_ELEMENTS(labels),
2957 sp_tweak_width_value_changed, 0.01, 0, 100 );
2958 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2959 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2960 }
2963 {
2964 /* Force */
2965 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
2966 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
2967 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
2968 _("Force"), _("Force:"), _("The force of the tweak action"),
2969 "tools.tweak", "force", 20,
2970 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
2971 1, 100, 1.0, 10.0,
2972 labels, values, G_N_ELEMENTS(labels),
2973 sp_tweak_force_value_changed, 0.01, 0, 100 );
2974 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2975 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2976 }
2978 /* Mode */
2979 {
2980 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2982 GtkTreeIter iter;
2983 gtk_list_store_append( model, &iter );
2984 gtk_list_store_set( model, &iter,
2985 0, _("Push mode"),
2986 1, _("Push parts of paths in any direction"),
2987 2, "tweak_push_mode",
2988 -1 );
2990 gtk_list_store_append( model, &iter );
2991 gtk_list_store_set( model, &iter,
2992 0, _("Shrink mode"),
2993 1, _("Shrink (inset) parts of paths"),
2994 2, "tweak_shrink_mode",
2995 -1 );
2997 gtk_list_store_append( model, &iter );
2998 gtk_list_store_set( model, &iter,
2999 0, _("Grow mode"),
3000 1, _("Grow (outset) parts of paths"),
3001 2, "tweak_grow_mode",
3002 -1 );
3004 gtk_list_store_append( model, &iter );
3005 gtk_list_store_set( model, &iter,
3006 0, _("Attract mode"),
3007 1, _("Attract parts of paths towards cursor"),
3008 2, "tweak_attract_mode",
3009 -1 );
3011 gtk_list_store_append( model, &iter );
3012 gtk_list_store_set( model, &iter,
3013 0, _("Repel mode"),
3014 1, _("Repel parts of paths from cursor"),
3015 2, "tweak_repel_mode",
3016 -1 );
3018 gtk_list_store_append( model, &iter );
3019 gtk_list_store_set( model, &iter,
3020 0, _("Roughen mode"),
3021 1, _("Roughen parts of paths"),
3022 2, "tweak_roughen_mode",
3023 -1 );
3025 gtk_list_store_append( model, &iter );
3026 gtk_list_store_set( model, &iter,
3027 0, _("Color paint mode"),
3028 1, _("Paint the tool's color upon selected objects"),
3029 2, "tweak_colorpaint_mode",
3030 -1 );
3032 gtk_list_store_append( model, &iter );
3033 gtk_list_store_set( model, &iter,
3034 0, _("Color jitter mode"),
3035 1, _("Jitter the colors of selected objects"),
3036 2, "tweak_colorjitter_mode",
3037 -1 );
3039 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
3040 g_object_set( act, "short_label", _("Mode:"), NULL );
3041 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3042 g_object_set_data( holder, "mode_action", act );
3044 ege_select_one_action_set_appearance( act, "full" );
3045 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3046 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3047 ege_select_one_action_set_icon_column( act, 2 );
3048 ege_select_one_action_set_tooltip_column( act, 1 );
3050 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3051 ege_select_one_action_set_active( act, mode );
3052 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3054 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3055 }
3057 guint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3059 {
3060 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3061 ege_output_action_set_use_markup( act, TRUE );
3062 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3063 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3064 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3065 g_object_set_data( holder, "tweak_channels_label", act);
3066 }
3068 {
3069 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3070 _("Hue"),
3071 _("In color mode, act on objects' hue"),
3072 NULL,
3073 Inkscape::ICON_SIZE_DECORATION );
3074 g_object_set( act, "short_label", _("H"), NULL );
3075 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3076 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3077 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doh", 1 ) );
3078 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3079 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3080 g_object_set_data( holder, "tweak_doh", act);
3081 }
3082 {
3083 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3084 _("Saturation"),
3085 _("In color mode, act on objects' saturation"),
3086 NULL,
3087 Inkscape::ICON_SIZE_DECORATION );
3088 g_object_set( act, "short_label", _("S"), NULL );
3089 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3090 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3091 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dos", 1 ) );
3092 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3093 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3094 g_object_set_data( holder, "tweak_dos", act );
3095 }
3096 {
3097 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3098 _("Lightness"),
3099 _("In color mode, act on objects' lightness"),
3100 NULL,
3101 Inkscape::ICON_SIZE_DECORATION );
3102 g_object_set( act, "short_label", _("L"), NULL );
3103 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3104 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3105 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dol", 1 ) );
3106 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3107 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3108 g_object_set_data( holder, "tweak_dol", act );
3109 }
3110 {
3111 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3112 _("Opacity"),
3113 _("In color mode, act on objects' opacity"),
3114 NULL,
3115 Inkscape::ICON_SIZE_DECORATION );
3116 g_object_set( act, "short_label", _("O"), NULL );
3117 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3118 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3119 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doo", 1 ) );
3120 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3121 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3122 g_object_set_data( holder, "tweak_doo", act );
3123 }
3125 { /* Fidelity */
3126 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3127 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3128 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3129 _("Fidelity"), _("Fidelity:"),
3130 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3131 "tools.tweak", "fidelity", 50,
3132 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3133 1, 100, 1.0, 10.0,
3134 labels, values, G_N_ELEMENTS(labels),
3135 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3136 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3137 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3138 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3139 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3140 g_object_set_data( holder, "tweak_fidelity", eact );
3141 }
3144 /* Use Pressure button */
3145 {
3146 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3147 _("Pressure"),
3148 _("Use the pressure of the input device to alter the force of tweak action"),
3149 "use_pressure",
3150 Inkscape::ICON_SIZE_DECORATION );
3151 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3152 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3153 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
3154 }
3156 }
3159 //########################
3160 //## Calligraphy ##
3161 //########################
3163 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3164 {
3165 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
3166 }
3168 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3169 {
3170 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
3171 }
3173 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3174 {
3175 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
3176 }
3178 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3179 {
3180 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
3181 }
3183 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3184 {
3185 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
3186 }
3188 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3189 {
3190 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
3191 }
3193 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3194 {
3195 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
3196 }
3198 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3199 {
3200 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
3201 }
3203 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3204 {
3205 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3206 }
3208 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer /*data*/ )
3209 {
3210 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
3211 }
3213 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
3214 {
3215 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3217 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
3218 }
3220 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
3221 {
3222 // FIXME: make defaults settable via Inkscape Options
3223 struct KeyValue {
3224 char const *key;
3225 double value;
3226 } const key_values[] = {
3227 {"mass", 0.02},
3228 {"wiggle", 0.0},
3229 {"angle", 30.0},
3230 {"width", 15},
3231 {"thinning", 0.1},
3232 {"tremor", 0.0},
3233 {"flatness", 0.9},
3234 {"cap_rounding", 0.0}
3235 };
3237 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
3238 KeyValue const &kv = key_values[i];
3239 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
3240 if ( adj ) {
3241 gtk_adjustment_set_value(adj, kv.value);
3242 }
3243 }
3244 }
3247 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3248 {
3249 {
3250 EgeAdjustmentAction* calligraphy_angle = 0;
3252 {
3253 /* Width */
3254 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
3255 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3256 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
3257 _("Pen Width"), _("Width:"),
3258 _("The width of the calligraphic pen (relative to the visible canvas area)"),
3259 "tools.calligraphic", "width", 15,
3260 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
3261 1, 100, 1.0, 10.0,
3262 labels, values, G_N_ELEMENTS(labels),
3263 sp_ddc_width_value_changed, 0.01, 0, 100 );
3264 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3265 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3266 }
3268 {
3269 /* Thinning */
3270 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
3271 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
3272 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
3273 _("Stroke Thinning"), _("Thinning:"),
3274 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
3275 "tools.calligraphic", "thinning", 0.1,
3276 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3277 -1.0, 1.0, 0.01, 0.1,
3278 labels, values, G_N_ELEMENTS(labels),
3279 sp_ddc_velthin_value_changed, 0.01, 2);
3280 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3281 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3282 }
3284 {
3285 /* Angle */
3286 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
3287 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3288 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
3289 _("Pen Angle"), _("Angle:"),
3290 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
3291 "tools.calligraphic", "angle", 30,
3292 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
3293 -90.0, 90.0, 1.0, 10.0,
3294 labels, values, G_N_ELEMENTS(labels),
3295 sp_ddc_angle_value_changed, 1, 0 );
3296 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3297 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3298 calligraphy_angle = eact;
3299 }
3301 {
3302 /* Fixation */
3303 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
3304 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
3305 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
3306 _("Fixation"), _("Fixation:"),
3307 _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
3308 "tools.calligraphic", "flatness", 0.9,
3309 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3310 0.0, 1.0, 0.01, 0.1,
3311 labels, values, G_N_ELEMENTS(labels),
3312 sp_ddc_flatness_value_changed, 0.01, 2 );
3313 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3314 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3315 }
3317 {
3318 /* Cap Rounding */
3319 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
3320 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
3321 // TRANSLATORS: "cap" means "end" (both start and finish) here
3322 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
3323 _("Cap rounding"), _("Caps:"),
3324 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
3325 "tools.calligraphic", "cap_rounding", 0.0,
3326 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3327 0.0, 5.0, 0.01, 0.1,
3328 labels, values, G_N_ELEMENTS(labels),
3329 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
3330 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3331 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3332 }
3334 {
3335 /* Tremor */
3336 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
3337 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
3338 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
3339 _("Stroke Tremor"), _("Tremor:"),
3340 _("Increase to make strokes rugged and trembling"),
3341 "tools.calligraphic", "tremor", 0.0,
3342 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3343 0.0, 1.0, 0.01, 0.1,
3344 labels, values, G_N_ELEMENTS(labels),
3345 sp_ddc_tremor_value_changed, 0.01, 2 );
3347 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3348 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3349 }
3351 {
3352 /* Wiggle */
3353 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
3354 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
3355 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
3356 _("Pen Wiggle"), _("Wiggle:"),
3357 _("Increase to make the pen waver and wiggle"),
3358 "tools.calligraphic", "wiggle", 0.0,
3359 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3360 0.0, 1.0, 0.01, 0.1,
3361 labels, values, G_N_ELEMENTS(labels),
3362 sp_ddc_wiggle_value_changed, 0.01, 2 );
3363 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3364 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3365 }
3367 {
3368 /* Mass */
3369 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
3370 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
3371 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
3372 _("Pen Mass"), _("Mass:"),
3373 _("Increase to make the pen drag behind, as if slowed by inertia"),
3374 "tools.calligraphic", "mass", 0.02,
3375 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3376 0.0, 1.0, 0.01, 0.1,
3377 labels, values, G_N_ELEMENTS(labels),
3378 sp_ddc_mass_value_changed, 0.01, 2 );
3379 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3380 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3381 }
3384 /* Trace Background button */
3385 {
3386 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
3387 _("Trace Background"),
3388 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
3389 "trace_background",
3390 Inkscape::ICON_SIZE_DECORATION );
3391 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3392 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
3393 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
3394 }
3396 /* Use Pressure button */
3397 {
3398 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
3399 _("Pressure"),
3400 _("Use the pressure of the input device to alter the width of the pen"),
3401 "use_pressure",
3402 Inkscape::ICON_SIZE_DECORATION );
3403 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3404 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
3405 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
3406 }
3408 /* Use Tilt button */
3409 {
3410 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
3411 _("Tilt"),
3412 _("Use the tilt of the input device to alter the angle of the pen's nib"),
3413 "use_tilt",
3414 Inkscape::ICON_SIZE_DECORATION );
3415 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3416 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
3417 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3418 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3419 }
3421 /* Reset */
3422 {
3423 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
3424 _("Defaults"),
3425 _("Reset all parameters to defaults"),
3426 GTK_STOCK_CLEAR );
3427 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
3428 gtk_action_group_add_action( mainActions, act );
3429 gtk_action_set_sensitive( act, TRUE );
3430 }
3431 }
3432 }
3435 //########################
3436 //## Circle / Arc ##
3437 //########################
3439 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
3440 {
3441 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
3442 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
3444 if (v1 == 0 && v2 == 0) {
3445 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
3446 gtk_action_set_sensitive( ocb, FALSE );
3447 gtk_action_set_sensitive( make_whole, FALSE );
3448 }
3449 } else {
3450 gtk_action_set_sensitive( ocb, TRUE );
3451 gtk_action_set_sensitive( make_whole, TRUE );
3452 }
3453 }
3455 static void
3456 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
3457 {
3458 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3460 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3461 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
3462 }
3464 // quit if run by the attr_changed listener
3465 if (g_object_get_data( tbl, "freeze" )) {
3466 return;
3467 }
3469 // in turn, prevent listener from responding
3470 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3472 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
3474 bool modmade = false;
3475 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3476 items != NULL;
3477 items = items->next)
3478 {
3479 SPItem *item = SP_ITEM(items->data);
3481 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
3483 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
3484 SPArc *arc = SP_ARC(item);
3486 if (!strcmp(value_name, "start"))
3487 ge->start = (adj->value * M_PI)/ 180;
3488 else
3489 ge->end = (adj->value * M_PI)/ 180;
3491 sp_genericellipse_normalize(ge);
3492 ((SPObject *)arc)->updateRepr();
3493 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
3495 modmade = true;
3496 }
3497 }
3499 g_free(namespaced_name);
3501 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
3503 sp_arctb_sensitivize( tbl, adj->value, other->value );
3505 if (modmade) {
3506 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
3507 _("Arc: Change start/end"));
3508 }
3510 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3511 }
3514 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
3515 {
3516 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
3517 }
3519 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
3520 {
3521 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
3522 }
3524 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
3525 {
3526 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3527 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3528 if ( ege_select_one_action_get_active( act ) != 0 ) {
3529 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
3530 } else {
3531 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
3532 }
3533 }
3535 // quit if run by the attr_changed listener
3536 if (g_object_get_data( tbl, "freeze" )) {
3537 return;
3538 }
3540 // in turn, prevent listener from responding
3541 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3543 bool modmade = false;
3545 if ( ege_select_one_action_get_active(act) != 0 ) {
3546 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3547 items != NULL;
3548 items = items->next)
3549 {
3550 if (SP_IS_ARC((SPItem *) items->data)) {
3551 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3552 repr->setAttribute("sodipodi:open", "true");
3553 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3554 modmade = true;
3555 }
3556 }
3557 } else {
3558 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3559 items != NULL;
3560 items = items->next)
3561 {
3562 if (SP_IS_ARC((SPItem *) items->data)) {
3563 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3564 repr->setAttribute("sodipodi:open", NULL);
3565 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3566 modmade = true;
3567 }
3568 }
3569 }
3571 if (modmade) {
3572 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
3573 _("Arc: Change open/closed"));
3574 }
3576 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3577 }
3579 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
3580 {
3581 GtkAdjustment *adj;
3582 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
3583 gtk_adjustment_set_value(adj, 0.0);
3584 gtk_adjustment_value_changed(adj);
3586 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
3587 gtk_adjustment_set_value(adj, 0.0);
3588 gtk_adjustment_value_changed(adj);
3590 spinbutton_defocus( GTK_OBJECT(obj) );
3591 }
3593 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3594 gchar const */*old_value*/, gchar const */*new_value*/,
3595 bool /*is_interactive*/, gpointer data)
3596 {
3597 GObject *tbl = G_OBJECT(data);
3599 // quit if run by the _changed callbacks
3600 if (g_object_get_data( tbl, "freeze" )) {
3601 return;
3602 }
3604 // in turn, prevent callbacks from responding
3605 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3607 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
3608 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
3610 GtkAdjustment *adj1,*adj2;
3611 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
3612 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
3613 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
3614 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
3616 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
3618 char const *openstr = NULL;
3619 openstr = repr->attribute("sodipodi:open");
3620 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
3622 if (openstr) {
3623 ege_select_one_action_set_active( ocb, 1 );
3624 } else {
3625 ege_select_one_action_set_active( ocb, 0 );
3626 }
3628 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3629 }
3631 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
3632 NULL, /* child_added */
3633 NULL, /* child_removed */
3634 arc_tb_event_attr_changed,
3635 NULL, /* content_changed */
3636 NULL /* order_changed */
3637 };
3640 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3641 {
3642 int n_selected = 0;
3643 Inkscape::XML::Node *repr = NULL;
3645 purge_repr_listener( tbl, tbl );
3647 for (GSList const *items = selection->itemList();
3648 items != NULL;
3649 items = items->next)
3650 {
3651 if (SP_IS_ARC((SPItem *) items->data)) {
3652 n_selected++;
3653 repr = SP_OBJECT_REPR((SPItem *) items->data);
3654 }
3655 }
3657 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3659 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3660 if (n_selected == 0) {
3661 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3662 } else if (n_selected == 1) {
3663 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3664 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3666 if (repr) {
3667 g_object_set_data( tbl, "repr", repr );
3668 Inkscape::GC::anchor(repr);
3669 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
3670 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
3671 }
3672 } else {
3673 // FIXME: implement averaging of all parameters for multiple selected
3674 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3675 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3676 sp_arctb_sensitivize( tbl, 1, 0 );
3677 }
3678 }
3681 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3682 {
3683 EgeAdjustmentAction* eact = 0;
3686 {
3687 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
3688 ege_output_action_set_use_markup( act, TRUE );
3689 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3690 g_object_set_data( holder, "mode_action", act );
3691 }
3693 /* Start */
3694 {
3695 eact = create_adjustment_action( "ArcStartAction",
3696 _("Start"), _("Start:"),
3697 _("The angle (in degrees) from the horizontal to the arc's start point"),
3698 "tools.shapes.arc", "start", 0.0,
3699 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
3700 -360.0, 360.0, 1.0, 10.0,
3701 0, 0, 0,
3702 sp_arctb_start_value_changed);
3703 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3704 }
3706 /* End */
3707 {
3708 eact = create_adjustment_action( "ArcEndAction",
3709 _("End"), _("End:"),
3710 _("The angle (in degrees) from the horizontal to the arc's end point"),
3711 "tools.shapes.arc", "end", 0.0,
3712 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3713 -360.0, 360.0, 1.0, 10.0,
3714 0, 0, 0,
3715 sp_arctb_end_value_changed);
3716 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3717 }
3719 /* Segments / Pie checkbox */
3720 {
3721 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3723 GtkTreeIter iter;
3724 gtk_list_store_append( model, &iter );
3725 gtk_list_store_set( model, &iter,
3726 0, _("Closed arc"),
3727 1, _("Switch to segment (closed shape with two radii)"),
3728 2, "circle_closed_arc",
3729 -1 );
3731 gtk_list_store_append( model, &iter );
3732 gtk_list_store_set( model, &iter,
3733 0, _("Open Arc"),
3734 1, _("Switch to arc (unclosed shape)"),
3735 2, "circle_open_arc",
3736 -1 );
3738 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
3739 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3740 g_object_set_data( holder, "open_action", act );
3742 ege_select_one_action_set_appearance( act, "full" );
3743 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3744 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3745 ege_select_one_action_set_icon_column( act, 2 );
3746 ege_select_one_action_set_tooltip_column( act, 1 );
3748 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
3749 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
3750 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
3751 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
3752 }
3754 /* Make Whole */
3755 {
3756 InkAction* inky = ink_action_new( "ArcResetAction",
3757 _("Make whole"),
3758 _("Make the shape a whole ellipse, not arc or segment"),
3759 "reset_circle",
3760 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3761 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
3762 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3763 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3764 g_object_set_data( holder, "make_whole", inky );
3765 }
3767 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
3768 // sensitivize make whole and open checkbox
3769 {
3770 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
3771 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
3772 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
3773 }
3776 sigc::connection *connection = new sigc::connection(
3777 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
3778 );
3779 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3780 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3781 }
3786 // toggle button callbacks and updaters
3788 //########################
3789 //## Dropper ##
3790 //########################
3792 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
3793 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
3794 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
3795 if ( set_action ) {
3796 if ( gtk_toggle_action_get_active( act ) ) {
3797 gtk_action_set_sensitive( set_action, TRUE );
3798 } else {
3799 gtk_action_set_sensitive( set_action, FALSE );
3800 }
3801 }
3803 spinbutton_defocus(GTK_OBJECT(tbl));
3804 }
3806 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
3807 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3808 spinbutton_defocus(GTK_OBJECT(tbl));
3809 }
3812 /**
3813 * Dropper auxiliary toolbar construction and setup.
3814 *
3815 * TODO: Would like to add swatch of current color.
3816 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3817 * can drag and drop places. Will provide a nice mixing palette.
3818 */
3819 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3820 {
3821 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
3823 {
3824 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
3825 _("Pick alpha"),
3826 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
3827 "color_alpha_get",
3828 Inkscape::ICON_SIZE_DECORATION );
3829 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3830 g_object_set_data( holder, "pick_action", act );
3831 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
3832 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
3833 }
3835 {
3836 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
3837 _("Set alpha"),
3838 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
3839 "color_alpha_set",
3840 Inkscape::ICON_SIZE_DECORATION );
3841 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3842 g_object_set_data( holder, "set_action", act );
3843 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
3844 // make sure it's disabled if we're not picking alpha
3845 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
3846 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
3847 }
3848 }
3851 //########################
3852 //## Text Toolbox ##
3853 //########################
3854 /*
3855 static void
3856 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3857 {
3858 //Call back for letter sizing spinbutton
3859 }
3861 static void
3862 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3863 {
3864 //Call back for line height spinbutton
3865 }
3867 static void
3868 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3869 {
3870 //Call back for horizontal kerning spinbutton
3871 }
3873 static void
3874 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3875 {
3876 //Call back for vertical kerning spinbutton
3877 }
3879 static void
3880 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3881 {
3882 //Call back for letter rotation spinbutton
3883 }*/
3885 namespace {
3887 bool visible = false;
3889 void
3890 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
3891 {
3892 SPStyle *query =
3893 sp_style_new (SP_ACTIVE_DOCUMENT);
3895 int result_family =
3896 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3898 int result_style =
3899 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3901 int result_numbers =
3902 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3904 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3906 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3907 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3908 {
3909 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3911 if (repr)
3912 {
3913 sp_style_read_from_repr (query, repr);
3914 }
3915 else
3916 {
3917 return;
3918 }
3919 }
3921 if (query->text)
3922 {
3923 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3924 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3925 gtk_entry_set_text (GTK_ENTRY (entry), "");
3927 } else if (query->text->font_family.value) {
3929 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3930 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3932 Gtk::TreePath path;
3933 try {
3934 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3935 } catch (...) {
3936 return;
3937 }
3939 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3940 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3942 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3944 gtk_tree_selection_select_path (tselection, path.gobj());
3945 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3947 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3948 }
3950 //Size
3951 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3952 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3953 g_object_set_data (tbl, "size-block", gpointer(1));
3954 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3955 g_object_set_data (tbl, "size-block", gpointer(0));
3956 free (str);
3958 //Anchor
3959 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3960 {
3961 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3962 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3963 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3964 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3965 }
3966 else
3967 {
3968 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3969 {
3970 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3971 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3972 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3973 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3974 }
3975 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3976 {
3977 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3978 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3979 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3980 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3981 }
3982 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3983 {
3984 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3985 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3986 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3987 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3988 }
3989 }
3991 //Style
3992 {
3993 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3995 gboolean active = gtk_toggle_button_get_active (button);
3996 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3998 if (active != check)
3999 {
4000 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4001 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4002 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4003 }
4004 }
4006 {
4007 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
4009 gboolean active = gtk_toggle_button_get_active (button);
4010 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
4012 if (active != check)
4013 {
4014 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4015 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4016 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4017 }
4018 }
4020 //Orientation
4021 //locking both buttons, changing one affect all group (both)
4022 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
4023 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4025 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
4026 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
4028 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
4029 {
4030 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4031 }
4032 else
4033 {
4034 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
4035 }
4036 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4037 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
4038 }
4040 sp_style_unref(query);
4041 }
4043 void
4044 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
4045 {
4046 sp_text_toolbox_selection_changed (selection, tbl);
4047 }
4049 void
4050 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4051 {
4052 sp_text_toolbox_selection_changed (NULL, tbl);
4053 }
4055 void
4056 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4057 GObject *tbl)
4058 {
4059 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4060 GtkTreeModel *model = 0;
4061 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4062 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4063 GtkTreeIter iter;
4064 char *family = 0;
4066 (void)popdown;
4068 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4069 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4071 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
4072 return;
4073 }
4075 gtk_tree_model_get (model, &iter, 0, &family, -1);
4077 if (g_object_get_data (G_OBJECT (selection), "block"))
4078 {
4079 gtk_entry_set_text (GTK_ENTRY (entry), family);
4080 return;
4081 }
4083 gtk_entry_set_text (GTK_ENTRY (entry), family);
4085 SPStyle *query =
4086 sp_style_new (SP_ACTIVE_DOCUMENT);
4088 int result_numbers =
4089 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4091 SPCSSAttr *css = sp_repr_css_attr_new ();
4092 sp_repr_css_set_property (css, "font-family", family);
4094 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4095 if (result_numbers == QUERY_STYLE_NOTHING)
4096 {
4097 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4098 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
4099 }
4100 else
4101 {
4102 sp_desktop_set_style (desktop, css, true, true);
4103 }
4105 sp_style_unref(query);
4107 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4108 _("Text: Change font family"));
4109 sp_repr_css_attr_unref (css);
4110 free (family);
4111 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4113 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4114 }
4116 void
4117 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
4118 GObject *tbl)
4119 {
4120 const char *family = gtk_entry_get_text (entry);
4122 try {
4123 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
4124 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4125 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4126 gtk_tree_selection_select_path (selection, path.gobj());
4127 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4128 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4129 } catch (...) {
4130 if (family && strlen (family))
4131 {
4132 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4133 }
4134 }
4135 }
4137 void
4138 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
4139 gpointer data)
4140 {
4141 if (g_object_get_data (G_OBJECT (button), "block")) return;
4142 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
4143 int prop = GPOINTER_TO_INT(data);
4145 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4146 SPCSSAttr *css = sp_repr_css_attr_new ();
4148 switch (prop)
4149 {
4150 case 0:
4151 {
4152 sp_repr_css_set_property (css, "text-anchor", "start");
4153 sp_repr_css_set_property (css, "text-align", "start");
4154 break;
4155 }
4156 case 1:
4157 {
4158 sp_repr_css_set_property (css, "text-anchor", "middle");
4159 sp_repr_css_set_property (css, "text-align", "center");
4160 break;
4161 }
4163 case 2:
4164 {
4165 sp_repr_css_set_property (css, "text-anchor", "end");
4166 sp_repr_css_set_property (css, "text-align", "end");
4167 break;
4168 }
4170 case 3:
4171 {
4172 sp_repr_css_set_property (css, "text-anchor", "start");
4173 sp_repr_css_set_property (css, "text-align", "justify");
4174 break;
4175 }
4176 }
4178 SPStyle *query =
4179 sp_style_new (SP_ACTIVE_DOCUMENT);
4180 int result_numbers =
4181 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4183 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4184 if (result_numbers == QUERY_STYLE_NOTHING)
4185 {
4186 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4187 }
4189 sp_style_unref(query);
4191 sp_desktop_set_style (desktop, css, true, true);
4192 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4193 _("Text: Change alignment"));
4194 sp_repr_css_attr_unref (css);
4196 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4197 }
4199 void
4200 sp_text_toolbox_style_toggled (GtkToggleButton *button,
4201 gpointer data)
4202 {
4203 if (g_object_get_data (G_OBJECT (button), "block")) return;
4205 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4206 SPCSSAttr *css = sp_repr_css_attr_new ();
4207 int prop = GPOINTER_TO_INT(data);
4208 bool active = gtk_toggle_button_get_active (button);
4211 switch (prop)
4212 {
4213 case 0:
4214 {
4215 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
4216 break;
4217 }
4219 case 1:
4220 {
4221 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
4222 break;
4223 }
4224 }
4226 SPStyle *query =
4227 sp_style_new (SP_ACTIVE_DOCUMENT);
4228 int result_numbers =
4229 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4231 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4232 if (result_numbers == QUERY_STYLE_NOTHING)
4233 {
4234 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4235 }
4237 sp_style_unref(query);
4239 sp_desktop_set_style (desktop, css, true, true);
4240 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4241 _("Text: Change font style"));
4242 sp_repr_css_attr_unref (css);
4244 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4245 }
4247 void
4248 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
4249 gpointer data)
4250 {
4251 if (g_object_get_data (G_OBJECT (button), "block")) {
4252 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4253 return;
4254 }
4256 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4257 SPCSSAttr *css = sp_repr_css_attr_new ();
4258 int prop = GPOINTER_TO_INT(data);
4260 switch (prop)
4261 {
4262 case 0:
4263 {
4264 sp_repr_css_set_property (css, "writing-mode", "lr");
4265 break;
4266 }
4268 case 1:
4269 {
4270 sp_repr_css_set_property (css, "writing-mode", "tb");
4271 break;
4272 }
4273 }
4275 SPStyle *query =
4276 sp_style_new (SP_ACTIVE_DOCUMENT);
4277 int result_numbers =
4278 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4280 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4281 if (result_numbers == QUERY_STYLE_NOTHING)
4282 {
4283 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4284 }
4286 sp_desktop_set_style (desktop, css, true, true);
4287 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4288 _("Text: Change orientation"));
4289 sp_repr_css_attr_unref (css);
4291 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4292 }
4294 gboolean
4295 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, gpointer /*data*/)
4296 {
4297 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4298 if (!desktop) return FALSE;
4300 switch (get_group0_keyval (event)) {
4301 case GDK_Escape: // defocus
4302 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4303 return TRUE; // I consumed the event
4304 break;
4305 case GDK_Return: // defocus
4306 case GDK_KP_Enter:
4307 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4308 return TRUE; // I consumed the event
4309 break;
4310 }
4311 return FALSE;
4312 }
4314 gboolean
4315 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4316 {
4317 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4318 if (!desktop) return FALSE;
4320 switch (get_group0_keyval (event)) {
4321 case GDK_Escape: // defocus
4322 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4323 sp_text_toolbox_selection_changed (NULL, tbl); // update
4324 return TRUE; // I consumed the event
4325 break;
4326 }
4327 return FALSE;
4328 }
4330 gboolean
4331 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
4332 {
4333 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4334 if (!desktop) return FALSE;
4336 switch (get_group0_keyval (event)) {
4337 case GDK_KP_Enter:
4338 case GDK_Return:
4339 case GDK_Escape: // defocus
4340 gtk_widget_hide (w);
4341 visible = false;
4342 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4343 return TRUE; // I consumed the event
4344 break;
4345 }
4346 return FALSE;
4347 }
4350 void
4351 sp_text_toolbox_size_changed (GtkComboBox *cbox,
4352 GObject *tbl)
4353 {
4354 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4356 if (g_object_get_data (tbl, "size-block")) return;
4358 char *text = gtk_combo_box_get_active_text (cbox);
4360 SPCSSAttr *css = sp_repr_css_attr_new ();
4361 sp_repr_css_set_property (css, "font-size", text);
4362 free (text);
4364 SPStyle *query =
4365 sp_style_new (SP_ACTIVE_DOCUMENT);
4366 int result_numbers =
4367 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4369 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4370 if (result_numbers == QUERY_STYLE_NOTHING)
4371 {
4372 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4373 }
4375 sp_style_unref(query);
4377 sp_desktop_set_style (desktop, css, true, true);
4378 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
4379 _("Text: Change font size"));
4380 sp_repr_css_attr_unref (css);
4383 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
4384 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4385 }
4387 void
4388 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
4389 GObject *tbl)
4390 {
4391 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4392 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4393 int x, y;
4395 if (!visible)
4396 {
4397 gdk_window_get_origin (widget->window, &x, &y);
4398 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
4399 gtk_widget_show_all (popdown);
4401 gdk_pointer_grab (widget->window, TRUE,
4402 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
4403 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
4404 GDK_POINTER_MOTION_MASK),
4405 NULL, NULL, GDK_CURRENT_TIME);
4407 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
4409 visible = true;
4410 }
4411 else
4412 {
4413 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4414 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4415 gtk_widget_hide (popdown);
4416 visible = false;
4417 }
4418 }
4420 gboolean
4421 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
4422 GdkEventFocus */*event*/,
4423 GObject */*tbl*/)
4424 {
4425 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
4426 return FALSE;
4427 }
4429 gboolean
4430 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
4431 GdkEventFocus */*event*/,
4432 GObject */*tbl*/)
4433 {
4434 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4436 gtk_widget_hide (popdown);
4437 visible = false;
4438 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4439 return TRUE;
4440 }
4442 void
4443 cell_data_func (GtkTreeViewColumn */*column*/,
4444 GtkCellRenderer *cell,
4445 GtkTreeModel *tree_model,
4446 GtkTreeIter *iter,
4447 gpointer /*data*/)
4448 {
4449 char *family,
4450 *family_escaped,
4451 *sample_escaped;
4453 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
4455 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
4457 family_escaped = g_markup_escape_text (family, -1);
4458 sample_escaped = g_markup_escape_text (sample, -1);
4460 std::stringstream markup;
4461 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
4462 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
4464 free (family);
4465 free (family_escaped);
4466 free (sample_escaped);
4467 }
4469 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
4470 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
4471 if (completion) {
4472 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
4473 g_object_unref (completion);
4474 }
4475 }
4477 GtkWidget*
4478 sp_text_toolbox_new (SPDesktop *desktop)
4479 {
4480 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
4482 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4483 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4485 GtkTooltips *tt = gtk_tooltips_new();
4486 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4488 ////////////Family
4489 //Window
4490 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4491 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4493 //Entry
4494 GtkWidget *entry = gtk_entry_new ();
4495 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4496 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4497 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4498 gtk_entry_completion_set_text_column (completion, 0);
4499 gtk_entry_completion_set_minimum_key_length (completion, 1);
4500 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4501 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4502 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4503 aux_toolbox_space (tbl, 1);
4504 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
4505 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
4507 //Button
4508 GtkWidget *button = gtk_button_new ();
4509 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
4510 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
4512 //Popdown
4513 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
4514 GtkWidget *treeview = gtk_tree_view_new ();
4516 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4517 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
4518 gtk_tree_view_column_pack_start (column, cell, FALSE);
4519 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
4520 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
4521 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4523 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
4524 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
4525 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
4527 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
4529 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
4530 gtk_container_add (GTK_CONTAINER (sw), treeview);
4532 gtk_container_add (GTK_CONTAINER (window), sw);
4533 gtk_widget_set_size_request (window, 300, 450);
4535 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
4536 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
4537 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
4539 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
4541 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
4542 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
4544 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
4545 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
4547 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
4548 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
4549 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
4550 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
4551 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
4553 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
4554 aux_toolbox_space (tbl, 1);
4555 GtkWidget *box = gtk_event_box_new ();
4556 gtk_container_add (GTK_CONTAINER (box), image);
4557 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
4558 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
4559 GtkTooltips *tooltips = gtk_tooltips_new ();
4560 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
4561 gtk_widget_hide (GTK_WIDGET (box));
4562 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
4564 ////////////Size
4565 const char *sizes[] = {
4566 "4", "6", "8", "9", "10", "11", "12", "13", "14",
4567 "16", "18", "20", "22", "24", "28",
4568 "32", "36", "40", "48", "56", "64", "72", "144"
4569 };
4571 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
4572 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
4573 gtk_widget_set_size_request (cbox, 80, -1);
4574 aux_toolbox_space (tbl, 1);
4575 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
4576 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
4577 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
4578 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
4580 //spacer
4581 aux_toolbox_space (tbl, 4);
4582 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4584 ////////////Text anchor
4585 GtkWidget *group = gtk_radio_button_new (NULL);
4586 GtkWidget *row = gtk_hbox_new (FALSE, 4);
4587 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
4589 // left
4590 GtkWidget *rbutton = group;
4591 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4592 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4593 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4595 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4596 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
4597 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
4598 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
4600 // center
4601 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4602 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4603 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
4604 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4606 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4607 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
4608 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
4609 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
4611 // right
4612 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4613 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4614 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4615 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4617 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4618 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
4619 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
4620 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
4622 // fill
4623 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4624 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4625 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
4626 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4628 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4629 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
4630 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
4631 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
4633 aux_toolbox_space (tbl, 1);
4634 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4636 //spacer
4637 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4639 ////////////Text style
4640 row = gtk_hbox_new (FALSE, 4);
4642 // bold
4643 rbutton = gtk_toggle_button_new ();
4644 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4645 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
4646 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4647 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
4649 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4650 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
4651 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
4653 // italic
4654 rbutton = gtk_toggle_button_new ();
4655 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4656 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
4657 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4658 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
4660 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4661 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
4662 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
4664 aux_toolbox_space (tbl, 1);
4665 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4667 //spacer
4668 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4670 ////////////Text orientation
4671 group = gtk_radio_button_new (NULL);
4672 row = gtk_hbox_new (FALSE, 4);
4673 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4675 // horizontal
4676 rbutton = group;
4677 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4678 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4679 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4680 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4682 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4683 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4684 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4686 // vertical
4687 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4688 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4689 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4690 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4691 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4693 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4694 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4695 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4696 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4699 //watch selection
4700 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4702 sigc::connection *c_selection_changed =
4703 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4704 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4705 pool->add_connection ("selection-changed", c_selection_changed);
4707 sigc::connection *c_selection_modified =
4708 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4709 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4710 pool->add_connection ("selection-modified", c_selection_modified);
4712 sigc::connection *c_subselection_changed =
4713 new sigc::connection (desktop->connectToolSubselectionChanged
4714 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4715 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4717 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4720 gtk_widget_show_all (tbl);
4721 return tbl;
4723 } // end of sp_text_toolbox_new()
4725 }//<unnamed> namespace
4728 //#########################
4729 //## Connector ##
4730 //#########################
4732 static void sp_connector_path_set_avoid(void)
4733 {
4734 cc_selection_set_avoid(true);
4735 }
4738 static void sp_connector_path_set_ignore(void)
4739 {
4740 cc_selection_set_avoid(false);
4741 }
4745 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4746 {
4747 // quit if run by the _changed callbacks
4748 if (g_object_get_data( tbl, "freeze" )) {
4749 return;
4750 }
4752 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4753 SPDocument *doc = sp_desktop_document(desktop);
4755 if (!sp_document_get_undo_sensitive(doc))
4756 {
4757 return;
4758 }
4760 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4762 if ( repr->attribute("inkscape:connector-spacing") ) {
4763 gdouble priorValue = gtk_adjustment_get_value(adj);
4764 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4765 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4766 return;
4767 }
4768 } else if ( adj->value == defaultConnSpacing ) {
4769 return;
4770 }
4772 // in turn, prevent callbacks from responding
4773 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4775 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4776 SP_OBJECT(desktop->namedview)->updateRepr();
4778 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4779 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4780 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4781 NR::Matrix m = NR::identity();
4782 avoid_item_move(&m, item);
4783 }
4785 if (items) {
4786 g_slist_free(items);
4787 }
4789 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4790 _("Change connector spacing"));
4792 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4794 spinbutton_defocus(GTK_OBJECT(tbl));
4795 }
4797 static void sp_connector_graph_layout(void)
4798 {
4799 if (!SP_ACTIVE_DESKTOP) return;
4801 // hack for clones, see comment in align-and-distribute.cpp
4802 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4803 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4805 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4807 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4809 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4810 }
4812 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4813 {
4814 if ( gtk_toggle_action_get_active( act ) ) {
4815 prefs_set_string_attribute("tools.connector", "directedlayout",
4816 "true");
4817 } else {
4818 prefs_set_string_attribute("tools.connector", "directedlayout",
4819 "false");
4820 }
4821 }
4823 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4824 {
4825 if ( gtk_toggle_action_get_active( act ) ) {
4826 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4827 "true");
4828 } else {
4829 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4830 "false");
4831 }
4832 }
4835 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4836 {
4837 prefs_set_double_attribute("tools.connector", "length", adj->value);
4838 spinbutton_defocus(GTK_OBJECT(tbl));
4839 }
4841 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4842 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
4843 bool /*is_interactive*/, gpointer data)
4844 {
4845 GtkWidget *tbl = GTK_WIDGET(data);
4847 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4848 return;
4849 }
4850 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4851 return;
4852 }
4854 GtkAdjustment *adj = (GtkAdjustment*)
4855 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4856 gdouble spacing = defaultConnSpacing;
4857 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4859 gtk_adjustment_set_value(adj, spacing);
4860 }
4863 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4864 NULL, /* child_added */
4865 NULL, /* child_removed */
4866 connector_tb_event_attr_changed,
4867 NULL, /* content_changed */
4868 NULL /* order_changed */
4869 };
4872 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
4873 {
4874 {
4875 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
4876 _("Avoid"),
4877 _("Make connectors avoid selected objects"),
4878 "connector_avoid",
4879 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4880 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
4881 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4882 }
4884 {
4885 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
4886 _("Ignore"),
4887 _("Make connectors ignore selected objects"),
4888 "connector_ignore",
4889 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4890 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
4891 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4892 }
4894 EgeAdjustmentAction* eact = 0;
4896 // Spacing spinbox
4897 eact = create_adjustment_action( "ConnectorSpacingAction",
4898 _("Connector Spacing"), _("Spacing:"),
4899 _("The amount of space left around objects by auto-routing connectors"),
4900 "tools.connector", "spacing", defaultConnSpacing,
4901 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
4902 0, 100, 1.0, 10.0,
4903 0, 0, 0,
4904 connector_spacing_changed, 1, 0 );
4905 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4907 // Graph (connector network) layout
4908 {
4909 InkAction* inky = ink_action_new( "ConnectorGraphAction",
4910 _("Graph"),
4911 _("Nicely arrange selected connector network"),
4912 "graph_layout",
4913 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4914 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
4915 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4916 }
4918 // Default connector length spinbox
4919 eact = create_adjustment_action( "ConnectorLengthAction",
4920 _("Connector Length"), _("Length:"),
4921 _("Ideal length for connectors when layout is applied"),
4922 "tools.connector", "length", 100,
4923 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
4924 10, 1000, 10.0, 100.0,
4925 0, 0, 0,
4926 connector_length_changed, 1, 0 );
4927 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4930 // Directed edges toggle button
4931 {
4932 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
4933 _("Downwards"),
4934 _("Make connectors with end-markers (arrows) point downwards"),
4935 "directed_graph",
4936 Inkscape::ICON_SIZE_DECORATION );
4937 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4939 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
4940 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4941 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4943 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
4944 }
4946 // Avoid overlaps toggle button
4947 {
4948 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
4949 _("Remove overlaps"),
4950 _("Do not allow overlapping shapes"),
4951 "remove_overlaps",
4952 Inkscape::ICON_SIZE_DECORATION );
4953 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4955 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
4956 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4957 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4959 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
4960 }
4962 // Code to watch for changes to the connector-spacing attribute in
4963 // the XML.
4964 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4965 g_assert(repr != NULL);
4967 purge_repr_listener( holder, holder );
4969 if (repr) {
4970 g_object_set_data( holder, "repr", repr );
4971 Inkscape::GC::anchor(repr);
4972 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
4973 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
4974 }
4975 } // end of sp_connector_toolbox_prep()
4978 //#########################
4979 //## Paintbucket ##
4980 //#########################
4982 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
4983 {
4984 gint channels = ege_select_one_action_get_active( act );
4985 flood_channels_set_channels( channels );
4986 }
4988 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
4989 {
4990 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4991 }
4993 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
4994 {
4995 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
4996 }
4998 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
4999 {
5000 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
5001 SPUnit const *unit = tracker->getActiveUnit();
5003 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
5005 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
5006 }
5008 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
5009 {
5010 // FIXME: make defaults settable via Inkscape Options
5011 struct KeyValue {
5012 char const *key;
5013 double value;
5014 } const key_values[] = {
5015 {"threshold", 15},
5016 {"offset", 0.0}
5017 };
5019 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
5020 KeyValue const &kv = key_values[i];
5021 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
5022 if ( adj ) {
5023 gtk_adjustment_set_value(adj, kv.value);
5024 }
5025 }
5027 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
5028 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
5029 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
5030 ege_select_one_action_set_active( autogap_action, 0 );
5031 }
5033 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5034 {
5035 EgeAdjustmentAction* eact = 0;
5037 {
5038 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5040 GList* items = 0;
5041 gint count = 0;
5042 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
5043 {
5044 GtkTreeIter iter;
5045 gtk_list_store_append( model, &iter );
5046 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5047 count++;
5048 }
5049 g_list_free( items );
5050 items = 0;
5051 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
5052 g_object_set( act1, "short_label", _("Fill by:"), NULL );
5053 ege_select_one_action_set_appearance( act1, "compact" );
5054 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
5055 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
5056 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
5057 g_object_set_data( holder, "channels_action", act1 );
5058 }
5060 // Spacing spinbox
5061 {
5062 eact = create_adjustment_action(
5063 "ThresholdAction",
5064 _("Fill Threshold"), _("Threshold:"),
5065 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
5066 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
5067 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
5068 0, 0, 0,
5069 paintbucket_threshold_changed, 1, 0 );
5071 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5072 }
5074 // Create the units menu.
5075 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
5076 tracker->setActiveUnit(sp_unit_get_by_abbreviation(prefs_get_string_attribute("tools.paintbucket", "offsetunits")));
5077 g_object_set_data( holder, "tracker", tracker );
5078 {
5079 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
5080 gtk_action_group_add_action( mainActions, act );
5081 }
5083 // Offset spinbox
5084 {
5085 eact = create_adjustment_action(
5086 "OffsetAction",
5087 _("Grow/shrink by"), _("Grow/shrink by:"),
5088 _("The amount to grow (positive) or shrink (negative) the created fill path"),
5089 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
5090 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
5091 0, 0, 0,
5092 paintbucket_offset_changed, 1, 2);
5093 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
5095 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5096 }
5098 /* Auto Gap */
5099 {
5100 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5102 GList* items = 0;
5103 gint count = 0;
5104 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
5105 {
5106 GtkTreeIter iter;
5107 gtk_list_store_append( model, &iter );
5108 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5109 count++;
5110 }
5111 g_list_free( items );
5112 items = 0;
5113 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
5114 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
5115 ege_select_one_action_set_appearance( act2, "compact" );
5116 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
5117 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
5118 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
5119 g_object_set_data( holder, "autogap_action", act2 );
5120 }
5122 /* Reset */
5123 {
5124 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
5125 _("Defaults"),
5126 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
5127 GTK_STOCK_CLEAR );
5128 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
5129 gtk_action_group_add_action( mainActions, act );
5130 gtk_action_set_sensitive( act, TRUE );
5131 }
5133 }
5135 /*
5136 Local Variables:
5137 mode:c++
5138 c-file-style:"stroustrup"
5139 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
5140 indent-tabs-mode:nil
5141 fill-column:99
5142 End:
5143 */
5144 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :