1 /** \file
2 * Controls bars for some of Inkscape's tools
3 * (for some tools, they are in their own files)
4 */
6 /*
7 *
8 * Authors:
9 * MenTaLguY <mental@rydia.net>
10 * Lauris Kaplinski <lauris@kaplinski.com>
11 * bulia byak <buliabyak@users.sf.net>
12 * Frank Felfe <innerspace@iname.com>
13 * John Cliff <simarilius@yahoo.com>
14 * David Turner <novalis@gnu.org>
15 * Josh Andler <scislac@scislac.com>
16 * Jon A. Cruz <jon@joncruz.org>
17 *
18 * Copyright (C) 2004 David Turner
19 * Copyright (C) 2003 MenTaLguY
20 * Copyright (C) 1999-2006 authors
21 * Copyright (C) 2001-2002 Ximian, Inc.
22 *
23 * Released under GNU GPL, read the file 'COPYING' for more information
24 */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <cstring>
31 #include <string>
33 #include <gtkmm.h>
34 #include <gtk/gtk.h>
35 #include <iostream>
36 #include <sstream>
38 #include "widgets/button.h"
39 #include "widgets/widget-sizes.h"
40 #include "widgets/spw-utilities.h"
41 #include "widgets/spinbutton-events.h"
42 #include "dialogs/text-edit.h"
43 #include "dialogs/dialog-events.h"
45 #include "ui/widget/style-swatch.h"
47 #include "prefs-utils.h"
48 #include "verbs.h"
49 #include "sp-namedview.h"
50 #include "desktop.h"
51 #include "desktop-handles.h"
52 #include "xml/repr.h"
53 #include "xml/node-event-vector.h"
54 #include <glibmm/i18n.h>
55 #include "helper/unit-menu.h"
56 #include "helper/units.h"
58 #include "inkscape.h"
59 #include "conn-avoid-ref.h"
62 #include "select-toolbar.h"
63 #include "gradient-toolbar.h"
65 #include "connector-context.h"
66 #include "node-context.h"
67 #include "shape-editor.h"
68 #include "tweak-context.h"
69 #include "sp-rect.h"
70 #include "box3d.h"
71 #include "box3d-context.h"
72 #include "sp-star.h"
73 #include "sp-spiral.h"
74 #include "sp-ellipse.h"
75 #include "sp-text.h"
76 #include "sp-flowtext.h"
77 #include "sp-clippath.h"
78 #include "sp-mask.h"
79 #include "style.h"
80 #include "selection.h"
81 #include "selection-chemistry.h"
82 #include "document-private.h"
83 #include "desktop-style.h"
84 #include "../libnrtype/font-lister.h"
85 #include "../libnrtype/font-instance.h"
86 #include "../connection-pool.h"
87 #include "../prefs-utils.h"
88 #include "../inkscape-stock.h"
89 #include "icon.h"
90 #include "graphlayout/graphlayout.h"
92 #include "mod360.h"
94 #include "toolbox.h"
96 #include "flood-context.h"
98 #include "ink-action.h"
99 #include "ege-adjustment-action.h"
100 #include "ege-output-action.h"
101 #include "ege-select-one-action.h"
102 #include "helper/unit-tracker.h"
104 #include "svg/css-ostringstream.h"
106 #include "widgets/calligraphic-profile-rename.h"
108 using Inkscape::UnitTracker;
110 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
111 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
113 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
118 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
120 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
121 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
122 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
123 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
124 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
125 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
126 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
127 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
129 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
132 static struct {
133 gchar const *type_name;
134 gchar const *data_name;
135 sp_verb_t verb;
136 sp_verb_t doubleclick_verb;
137 } const tools[] = {
138 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
139 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
140 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
141 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
142 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
143 { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
144 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
145 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
146 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
147 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
148 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
149 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
150 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
151 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
152 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
153 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
154 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
155 { NULL, NULL, 0, 0 }
156 };
158 static struct {
159 gchar const *type_name;
160 gchar const *data_name;
161 GtkWidget *(*create_func)(SPDesktop *desktop);
162 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
163 gchar const *ui_name;
164 gint swatch_verb_id;
165 gchar const *swatch_tool;
166 gchar const *swatch_tip;
167 } const aux_toolboxes[] = {
168 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
169 SP_VERB_INVALID, 0, 0},
170 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
171 SP_VERB_INVALID, 0, 0},
172 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
173 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", _("Color/opacity used for color tweaking")},
174 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
175 SP_VERB_INVALID, 0, 0},
176 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
177 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
178 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
179 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
180 { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar",
181 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
182 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
183 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
184 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
185 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
186 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
187 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
188 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
189 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
190 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
191 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
192 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
193 SP_VERB_INVALID, 0, 0},
194 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
195 SP_VERB_INVALID, 0, 0},
196 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
197 SP_VERB_INVALID, 0, 0},
198 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
199 SP_VERB_INVALID, 0, 0},
200 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
201 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
202 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
203 };
206 static gchar const * ui_descr =
207 "<ui>"
208 " <toolbar name='SelectToolbar'>"
209 " <toolitem action='EditSelectAll' />"
210 " <toolitem action='EditSelectAllInAllLayers' />"
211 " <toolitem action='EditDeselect' />"
212 " <separator />"
213 " <toolitem action='ObjectRotate90CCW' />"
214 " <toolitem action='ObjectRotate90' />"
215 " <toolitem action='ObjectFlipHorizontally' />"
216 " <toolitem action='ObjectFlipVertically' />"
217 " <separator />"
218 " <toolitem action='SelectionToBack' />"
219 " <toolitem action='SelectionLower' />"
220 " <toolitem action='SelectionRaise' />"
221 " <toolitem action='SelectionToFront' />"
222 " <separator />"
223 " <toolitem action='XAction' />"
224 " <toolitem action='YAction' />"
225 " <toolitem action='WidthAction' />"
226 " <toolitem action='LockAction' />"
227 " <toolitem action='HeightAction' />"
228 " <toolitem action='UnitsAction' />"
229 " <separator />"
230 " <toolitem action='transform_affect_label' />"
231 " <toolitem action='transform_stroke' />"
232 " <toolitem action='transform_corners' />"
233 " <toolitem action='transform_gradient' />"
234 " <toolitem action='transform_pattern' />"
235 " </toolbar>"
237 " <toolbar name='NodeToolbar'>"
238 " <toolitem action='NodeInsertAction' />"
239 " <toolitem action='NodeDeleteAction' />"
240 " <separator />"
241 " <toolitem action='NodeJoinAction' />"
242 " <toolitem action='NodeJoinSegmentAction' />"
243 " <toolitem action='NodeDeleteSegmentAction' />"
244 " <toolitem action='NodeBreakAction' />"
245 " <separator />"
246 " <toolitem action='NodeCuspAction' />"
247 " <toolitem action='NodeSmoothAction' />"
248 " <toolitem action='NodeSymmetricAction' />"
249 " <separator />"
250 " <toolitem action='NodeLineAction' />"
251 " <toolitem action='NodeCurveAction' />"
252 " <separator />"
253 " <toolitem action='ObjectToPath' />"
254 " <toolitem action='StrokeToPath' />"
255 " <separator />"
256 " <toolitem action='NodeXAction' />"
257 " <toolitem action='NodeYAction' />"
258 " <toolitem action='NodeUnitsAction' />"
259 " <separator />"
260 " <toolitem action='ObjectEditClipPathAction' />"
261 " <toolitem action='ObjectEditMaskPathAction' />"
262 " <toolitem action='EditNextLPEParameterAction' />"
263 " <separator />"
264 " <toolitem action='NodesShowHandlesAction' />"
265 " <toolitem action='NodesShowHelperpath' />"
266 " </toolbar>"
268 " <toolbar name='TweakToolbar'>"
269 " <toolitem action='TweakWidthAction' />"
270 " <separator />"
271 " <toolitem action='TweakForceAction' />"
272 " <toolitem action='TweakPressureAction' />"
273 " <separator />"
274 " <toolitem action='TweakModeAction' />"
275 " <separator />"
276 " <toolitem action='TweakFidelityAction' />"
277 " <separator />"
278 " <toolitem action='TweakChannelsLabel' />"
279 " <toolitem action='TweakDoH' />"
280 " <toolitem action='TweakDoS' />"
281 " <toolitem action='TweakDoL' />"
282 " <toolitem action='TweakDoO' />"
283 " </toolbar>"
285 " <toolbar name='ZoomToolbar'>"
286 " <toolitem action='ZoomIn' />"
287 " <toolitem action='ZoomOut' />"
288 " <separator />"
289 " <toolitem action='Zoom1:0' />"
290 " <toolitem action='Zoom1:2' />"
291 " <toolitem action='Zoom2:1' />"
292 " <separator />"
293 " <toolitem action='ZoomSelection' />"
294 " <toolitem action='ZoomDrawing' />"
295 " <toolitem action='ZoomPage' />"
296 " <toolitem action='ZoomPageWidth' />"
297 " <separator />"
298 " <toolitem action='ZoomPrev' />"
299 " <toolitem action='ZoomNext' />"
300 " </toolbar>"
302 " <toolbar name='StarToolbar'>"
303 " <separator />"
304 " <toolitem action='StarStateAction' />"
305 " <separator />"
306 " <toolitem action='FlatAction' />"
307 " <separator />"
308 " <toolitem action='MagnitudeAction' />"
309 " <toolitem action='SpokeAction' />"
310 " <toolitem action='RoundednessAction' />"
311 " <toolitem action='RandomizationAction' />"
312 " <separator />"
313 " <toolitem action='StarResetAction' />"
314 " </toolbar>"
316 " <toolbar name='RectToolbar'>"
317 " <toolitem action='RectStateAction' />"
318 " <toolitem action='RectWidthAction' />"
319 " <toolitem action='RectHeightAction' />"
320 " <toolitem action='RadiusXAction' />"
321 " <toolitem action='RadiusYAction' />"
322 " <toolitem action='RectUnitsAction' />"
323 " <separator />"
324 " <toolitem action='RectResetAction' />"
325 " </toolbar>"
327 " <toolbar name='3DBoxToolbar'>"
328 " <toolitem action='3DBoxAngleXAction' />"
329 " <toolitem action='3DBoxVPXStateAction' />"
330 " <separator />"
331 " <toolitem action='3DBoxAngleYAction' />"
332 " <toolitem action='3DBoxVPYStateAction' />"
333 " <separator />"
334 " <toolitem action='3DBoxAngleZAction' />"
335 " <toolitem action='3DBoxVPZStateAction' />"
336 " </toolbar>"
338 " <toolbar name='SpiralToolbar'>"
339 " <toolitem action='SpiralStateAction' />"
340 " <toolitem action='SpiralRevolutionAction' />"
341 " <toolitem action='SpiralExpansionAction' />"
342 " <toolitem action='SpiralT0Action' />"
343 " <separator />"
344 " <toolitem action='SpiralResetAction' />"
345 " </toolbar>"
347 " <toolbar name='PenToolbar'>"
348 " </toolbar>"
350 " <toolbar name='PencilToolbar'>"
351 " </toolbar>"
353 " <toolbar name='CalligraphyToolbar'>"
354 " <separator />"
355 " <toolitem action='SetProfileAction'/>"
356 " <toolitem action='SaveDeleteProfileAction'/>"
357 " <separator />"
358 " <toolitem action='CalligraphyWidthAction' />"
359 " <toolitem action='PressureAction' />"
360 " <toolitem action='TraceAction' />"
361 " <toolitem action='ThinningAction' />"
362 " <separator />"
363 " <toolitem action='AngleAction' />"
364 " <toolitem action='TiltAction' />"
365 " <toolitem action='FixationAction' />"
366 " <separator />"
367 " <toolitem action='CapRoundingAction' />"
368 " <separator />"
369 " <toolitem action='TremorAction' />"
370 " <toolitem action='WiggleAction' />"
371 " <toolitem action='MassAction' />"
372 " <separator />"
373 " </toolbar>"
375 " <toolbar name='ArcToolbar'>"
376 " <toolitem action='ArcStateAction' />"
377 " <separator />"
378 " <toolitem action='ArcStartAction' />"
379 " <toolitem action='ArcEndAction' />"
380 " <separator />"
381 " <toolitem action='ArcOpenAction' />"
382 " <separator />"
383 " <toolitem action='ArcResetAction' />"
384 " <separator />"
385 " </toolbar>"
387 " <toolbar name='PaintbucketToolbar'>"
388 " <toolitem action='ChannelsAction' />"
389 " <separator />"
390 " <toolitem action='ThresholdAction' />"
391 " <separator />"
392 " <toolitem action='OffsetAction' />"
393 " <toolitem action='PaintbucketUnitsAction' />"
394 " <separator />"
395 " <toolitem action='AutoGapAction' />"
396 " <separator />"
397 " <toolitem action='PaintbucketResetAction' />"
398 " </toolbar>"
400 " <toolbar name='DropperToolbar'>"
401 " <toolitem action='DropperOpacityAction' />"
402 " <toolitem action='DropperPickAlphaAction' />"
403 " <toolitem action='DropperSetAlphaAction' />"
404 " </toolbar>"
406 " <toolbar name='ConnectorToolbar'>"
407 " <toolitem action='ConnectorAvoidAction' />"
408 " <toolitem action='ConnectorIgnoreAction' />"
409 " <toolitem action='ConnectorSpacingAction' />"
410 " <toolitem action='ConnectorGraphAction' />"
411 " <toolitem action='ConnectorLengthAction' />"
412 " <toolitem action='ConnectorDirectedAction' />"
413 " <toolitem action='ConnectorOverlapAction' />"
414 " </toolbar>"
416 "</ui>"
417 ;
419 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
421 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
423 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
424 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
426 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
427 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
429 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
430 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
432 /* Global text entry widgets necessary for update */
433 /* GtkWidget *dropper_rgb_entry,
434 *dropper_opacity_entry ; */
435 // should be made a private member once this is converted to class
437 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
438 connection->disconnect();
439 delete connection;
440 }
442 static void purge_repr_listener( GObject* obj, GObject* tbl )
443 {
444 (void)obj;
445 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
446 if (oldrepr) { // remove old listener
447 sp_repr_remove_listener_by_data(oldrepr, tbl);
448 Inkscape::GC::release(oldrepr);
449 oldrepr = 0;
450 g_object_set_data( tbl, "repr", NULL );
451 }
452 }
454 GtkWidget *
455 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
456 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
457 Inkscape::UI::View::View *view, GtkTooltips *tt)
458 {
459 SPAction *action = verb->get_action(view);
460 if (!action) return NULL;
462 SPAction *doubleclick_action;
463 if (doubleclick_verb)
464 doubleclick_action = doubleclick_verb->get_action(view);
465 else
466 doubleclick_action = NULL;
468 /* fixme: Handle sensitive/unsensitive */
469 /* fixme: Implement sp_button_new_from_action */
470 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
471 gtk_widget_show(b);
472 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
474 return b;
475 }
477 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
478 Inkscape::UI::View::View *view, GtkTooltips *tt)
479 {
480 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
481 }
483 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
484 Inkscape::UI::View::View *view, GtkTooltips *tt)
485 {
486 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
487 }
490 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
491 {
492 SPAction* targetAction = SP_ACTION(user_data);
493 if ( targetAction ) {
494 sp_action_perform( targetAction, NULL );
495 }
496 }
498 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
499 {
500 if ( data ) {
501 GtkAction* act = GTK_ACTION(data);
502 gtk_action_set_sensitive( act, sensitive );
503 }
504 }
506 static SPActionEventVector action_event_vector = {
507 {NULL},
508 NULL,
509 NULL,
510 sp_action_action_set_sensitive,
511 NULL,
512 NULL
513 };
515 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
516 {
517 GtkAction* act = 0;
519 SPAction* targetAction = verb->get_action(view);
520 InkAction* inky = ink_action_new( verb->get_id(), _(verb->get_name()), verb->get_tip(), verb->get_image(), size );
521 act = GTK_ACTION(inky);
522 gtk_action_set_sensitive( act, targetAction->sensitive );
524 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
526 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
527 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
529 return act;
530 }
532 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
533 {
534 Inkscape::UI::View::View *view = desktop;
535 gint verbsToUse[] = {
536 // disabled until we have icons for them:
537 //find
538 //SP_VERB_EDIT_TILE,
539 //SP_VERB_EDIT_UNTILE,
540 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
541 SP_VERB_DIALOG_DISPLAY,
542 SP_VERB_DIALOG_FILL_STROKE,
543 SP_VERB_DIALOG_NAMEDVIEW,
544 SP_VERB_DIALOG_TEXT,
545 SP_VERB_DIALOG_XML_EDITOR,
546 SP_VERB_EDIT_CLONE,
547 SP_VERB_EDIT_COPY,
548 SP_VERB_EDIT_CUT,
549 SP_VERB_EDIT_DUPLICATE,
550 SP_VERB_EDIT_PASTE,
551 SP_VERB_EDIT_REDO,
552 SP_VERB_EDIT_UNDO,
553 SP_VERB_EDIT_UNLINK_CLONE,
554 SP_VERB_FILE_EXPORT,
555 SP_VERB_FILE_IMPORT,
556 SP_VERB_FILE_NEW,
557 SP_VERB_FILE_OPEN,
558 SP_VERB_FILE_PRINT,
559 SP_VERB_FILE_SAVE,
560 SP_VERB_OBJECT_TO_CURVE,
561 SP_VERB_SELECTION_GROUP,
562 SP_VERB_SELECTION_OUTLINE,
563 SP_VERB_SELECTION_UNGROUP,
564 SP_VERB_ZOOM_1_1,
565 SP_VERB_ZOOM_1_2,
566 SP_VERB_ZOOM_2_1,
567 SP_VERB_ZOOM_DRAWING,
568 SP_VERB_ZOOM_IN,
569 SP_VERB_ZOOM_NEXT,
570 SP_VERB_ZOOM_OUT,
571 SP_VERB_ZOOM_PAGE,
572 SP_VERB_ZOOM_PAGE_WIDTH,
573 SP_VERB_ZOOM_PREV,
574 SP_VERB_ZOOM_SELECTION,
575 };
577 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
578 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
580 static std::map<SPDesktop*, GtkActionGroup*> groups;
581 GtkActionGroup* mainActions = 0;
582 if ( groups.find(desktop) != groups.end() ) {
583 mainActions = groups[desktop];
584 }
586 if ( !mainActions ) {
587 mainActions = gtk_action_group_new("main");
588 groups[desktop] = mainActions;
589 }
591 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
592 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
593 if ( verb ) {
594 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
595 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
596 gtk_action_group_add_action( mainActions, act );
597 }
598 }
599 }
601 return mainActions;
602 }
605 GtkWidget *
606 sp_tool_toolbox_new()
607 {
608 GtkTooltips *tt = gtk_tooltips_new();
609 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
611 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
612 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
614 gtk_widget_set_sensitive(tb, FALSE);
616 GtkWidget *hb = gtk_handle_box_new();
617 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
618 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
619 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
621 gtk_container_add(GTK_CONTAINER(hb), tb);
622 gtk_widget_show(GTK_WIDGET(tb));
624 sigc::connection* conn = new sigc::connection;
625 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
627 return hb;
628 }
630 static void
631 aux_toolbox_attached(GtkHandleBox */*toolbox*/, GtkWidget *child)
632 {
633 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
634 gtk_widget_queue_resize(child);
635 }
637 static void
638 aux_toolbox_detached(GtkHandleBox */*toolbox*/, GtkWidget *child)
639 {
640 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
641 gtk_widget_queue_resize(child);
642 }
644 GtkWidget *
645 sp_aux_toolbox_new()
646 {
647 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
649 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
651 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
653 gtk_widget_set_sensitive(tb, FALSE);
655 GtkWidget *hb = gtk_handle_box_new();
656 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
657 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
658 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
660 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
661 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
663 gtk_container_add(GTK_CONTAINER(hb), tb);
664 gtk_widget_show(GTK_WIDGET(tb));
666 sigc::connection* conn = new sigc::connection;
667 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
669 return hb;
670 }
672 //####################################
673 //# Commands Bar
674 //####################################
676 GtkWidget *
677 sp_commands_toolbox_new()
678 {
679 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
681 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
683 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
684 gtk_widget_set_sensitive(tb, FALSE);
686 GtkWidget *hb = gtk_handle_box_new();
687 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
688 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
689 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
691 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
692 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
694 gtk_container_add(GTK_CONTAINER(hb), tb);
695 gtk_widget_show(GTK_WIDGET(tb));
697 sigc::connection* conn = new sigc::connection;
698 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
700 return hb;
701 }
703 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
704 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
705 gchar const *path, gchar const *data, gdouble def,
706 GtkWidget *focusTarget,
707 GtkWidget *us,
708 GObject *dataKludge,
709 gboolean altx, gchar const *altx_mark,
710 gdouble lower, gdouble upper, gdouble step, gdouble page,
711 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
712 void (*callback)(GtkAdjustment *, GObject *),
713 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
714 {
715 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
716 lower, upper, step, page, page ) );
717 if (us) {
718 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
719 }
721 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
723 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
724 if ( shortLabel ) {
725 g_object_set( act, "short_label", shortLabel, NULL );
726 }
728 if ( (descrCount > 0) && descrLabels && descrValues ) {
729 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
730 }
732 if ( focusTarget ) {
733 ege_adjustment_action_set_focuswidget( act, focusTarget );
734 }
736 if ( altx && altx_mark ) {
737 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
738 }
740 if ( dataKludge ) {
741 g_object_set_data( dataKludge, data, adj );
742 }
744 // Using a cast just to make sure we pass in the right kind of function pointer
745 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
747 return act;
748 }
751 //####################################
752 //# node editing callbacks
753 //####################################
755 /**
756 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
757 */
758 static ShapeEditor *get_current_shape_editor()
759 {
760 if (!SP_ACTIVE_DESKTOP) {
761 return NULL;
762 }
764 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
766 if (!SP_IS_NODE_CONTEXT(event_context)) {
767 return NULL;
768 }
770 return SP_NODE_CONTEXT(event_context)->shape_editor;
771 }
774 void
775 sp_node_path_edit_add(void)
776 {
777 ShapeEditor *shape_editor = get_current_shape_editor();
778 if (shape_editor) shape_editor->add_node();
779 }
781 void
782 sp_node_path_edit_delete(void)
783 {
784 ShapeEditor *shape_editor = get_current_shape_editor();
785 if (shape_editor) shape_editor->delete_nodes();
786 }
788 void
789 sp_node_path_edit_delete_segment(void)
790 {
791 ShapeEditor *shape_editor = get_current_shape_editor();
792 if (shape_editor) shape_editor->delete_segment();
793 }
795 void
796 sp_node_path_edit_break(void)
797 {
798 ShapeEditor *shape_editor = get_current_shape_editor();
799 if (shape_editor) shape_editor->break_at_nodes();
800 }
802 void
803 sp_node_path_edit_join(void)
804 {
805 ShapeEditor *shape_editor = get_current_shape_editor();
806 if (shape_editor) shape_editor->join_nodes();
807 }
809 void
810 sp_node_path_edit_join_segment(void)
811 {
812 ShapeEditor *shape_editor = get_current_shape_editor();
813 if (shape_editor) shape_editor->join_segments();
814 }
816 void
817 sp_node_path_edit_toline(void)
818 {
819 ShapeEditor *shape_editor = get_current_shape_editor();
820 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
821 }
823 void
824 sp_node_path_edit_tocurve(void)
825 {
826 ShapeEditor *shape_editor = get_current_shape_editor();
827 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
828 }
830 void
831 sp_node_path_edit_cusp(void)
832 {
833 ShapeEditor *shape_editor = get_current_shape_editor();
834 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
835 }
837 void
838 sp_node_path_edit_smooth(void)
839 {
840 ShapeEditor *shape_editor = get_current_shape_editor();
841 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
842 }
844 void
845 sp_node_path_edit_symmetrical(void)
846 {
847 ShapeEditor *shape_editor = get_current_shape_editor();
848 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
849 }
851 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
852 bool show = gtk_toggle_action_get_active( act );
853 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
854 ShapeEditor *shape_editor = get_current_shape_editor();
855 if (shape_editor) shape_editor->show_handles(show);
856 }
858 static void toggle_show_helperpath (GtkToggleAction *act, gpointer /*data*/) {
859 bool show = gtk_toggle_action_get_active( act );
860 prefs_set_int_attribute ("tools.nodes", "show_helperpath", show ? 1 : 0);
861 ShapeEditor *shape_editor = get_current_shape_editor();
862 if (shape_editor) shape_editor->show_helperpath(show);
863 }
865 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
866 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
867 }
869 void sp_node_path_edit_clippath (GtkAction */*act*/, gpointer data) {
870 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), true);
871 }
873 void sp_node_path_edit_maskpath (GtkAction */*act*/, gpointer data) {
874 sp_selection_edit_clip_or_mask( reinterpret_cast<SPDesktop*>(data), false);
875 }
877 /* is called when the node selection is modified */
878 static void
879 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
880 {
881 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
882 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
883 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
884 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
886 // quit if run by the attr_changed listener
887 if (g_object_get_data( tbl, "freeze" )) {
888 return;
889 }
891 // in turn, prevent listener from responding
892 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
894 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
895 SPUnit const *unit = tracker->getActiveUnit();
897 ShapeEditor *shape_editor = get_current_shape_editor();
898 if (shape_editor && shape_editor->has_nodepath()) {
899 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
900 int n_selected = 0;
901 if (nodepath) {
902 n_selected = nodepath->numSelected();
903 }
905 if (n_selected == 0) {
906 gtk_action_set_sensitive(xact, FALSE);
907 gtk_action_set_sensitive(yact, FALSE);
908 } else {
909 gtk_action_set_sensitive(xact, TRUE);
910 gtk_action_set_sensitive(yact, TRUE);
911 NR::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
912 NR::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
914 if (n_selected == 1) {
915 NR::Point sel_node = nodepath->singleSelectedCoords();
916 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
917 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[NR::X], *unit));
918 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[NR::Y], *unit));
919 }
920 } else {
921 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
922 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
923 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
924 /* Note: Currently x and y will always have a value, even if the coordinates of the
925 selected nodes don't coincide (in this case we use the coordinates of the center
926 of the bounding box). So the entries are never set to zero. */
927 // FIXME: Maybe we should clear the entry if several nodes are selected
928 // instead of providing a kind of average value
929 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
930 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
931 }
932 }
933 }
934 } else {
935 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
936 gtk_action_set_sensitive(xact, FALSE);
937 gtk_action_set_sensitive(yact, FALSE);
938 }
940 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
941 }
943 static void
944 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
945 {
946 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
948 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
949 SPUnit const *unit = tracker->getActiveUnit();
951 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
952 prefs_set_double_attribute("tools.nodes", value_name, sp_units_get_pixels(adj->value, *unit));
953 }
955 // quit if run by the attr_changed listener
956 if (g_object_get_data( tbl, "freeze" )) {
957 return;
958 }
960 // in turn, prevent listener from responding
961 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
963 ShapeEditor *shape_editor = get_current_shape_editor();
964 if (shape_editor && shape_editor->has_nodepath()) {
965 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
966 if (!strcmp(value_name, "x")) {
967 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::X);
968 }
969 if (!strcmp(value_name, "y")) {
970 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::Y);
971 }
972 }
974 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
975 }
977 static void
978 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
979 {
980 sp_node_path_value_changed(adj, tbl, "x");
981 }
983 static void
984 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
985 {
986 sp_node_path_value_changed(adj, tbl, "y");
987 }
989 void
990 sp_node_toolbox_sel_changed (Inkscape::Selection *selection, GObject *tbl)
991 {
992 {
993 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_lpeedit" ) );
994 SPItem *item = selection->singleItem();
995 if (item && SP_IS_SHAPE(item)) {
996 LivePathEffectObject *lpeobj = sp_shape_get_livepatheffectobject(SP_SHAPE(item));
997 if (lpeobj) {
998 gtk_action_set_sensitive(w, TRUE);
999 } else {
1000 gtk_action_set_sensitive(w, FALSE);
1001 }
1002 } else {
1003 gtk_action_set_sensitive(w, FALSE);
1004 }
1005 }
1007 {
1008 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_clippathedit" ) );
1009 SPItem *item = selection->singleItem();
1010 if (item && item->clip_ref && item->clip_ref->getObject()) {
1011 gtk_action_set_sensitive(w, TRUE);
1012 } else {
1013 gtk_action_set_sensitive(w, FALSE);
1014 }
1015 }
1017 {
1018 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "nodes_maskedit" ) );
1019 SPItem *item = selection->singleItem();
1020 if (item && item->mask_ref && item->mask_ref->getObject()) {
1021 gtk_action_set_sensitive(w, TRUE);
1022 } else {
1023 gtk_action_set_sensitive(w, FALSE);
1024 }
1025 }
1026 }
1028 void
1029 sp_node_toolbox_sel_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
1030 {
1031 sp_node_toolbox_sel_changed (selection, tbl);
1032 }
1036 //################################
1037 //## Node Editing Toolbox ##
1038 //################################
1040 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1041 {
1042 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1043 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1044 g_object_set_data( holder, "tracker", tracker );
1046 {
1047 InkAction* inky = ink_action_new( "NodeInsertAction",
1048 _("Insert node"),
1049 _("Insert new nodes into selected segments"),
1050 "node_insert",
1051 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1052 g_object_set( inky, "short_label", _("Insert"), NULL );
1053 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
1054 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1055 }
1057 {
1058 InkAction* inky = ink_action_new( "NodeDeleteAction",
1059 _("Delete node"),
1060 _("Delete selected nodes"),
1061 "node_delete",
1062 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1063 g_object_set( inky, "short_label", _("Delete"), NULL );
1064 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
1065 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1066 }
1068 {
1069 InkAction* inky = ink_action_new( "NodeJoinAction",
1070 _("Join endnodes"),
1071 _("Join selected endnodes"),
1072 "node_join",
1073 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1074 g_object_set( inky, "short_label", _("Join"), NULL );
1075 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1076 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1077 }
1079 {
1080 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1081 _("Join Segment"),
1082 _("Join selected endnodes with a new segment"),
1083 "node_join_segment",
1084 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1085 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1086 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1087 }
1089 {
1090 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1091 _("Delete Segment"),
1092 _("Split path between two non-endpoint nodes"),
1093 "node_delete_segment",
1094 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1095 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1096 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1097 }
1099 {
1100 InkAction* inky = ink_action_new( "NodeBreakAction",
1101 _("Node Break"),
1102 _("Break path at selected nodes"),
1103 "node_break",
1104 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1105 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1106 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1107 }
1109 {
1110 InkAction* inky = ink_action_new( "NodeCuspAction",
1111 _("Node Cusp"),
1112 _("Make selected nodes corner"),
1113 "node_cusp",
1114 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1115 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1116 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1117 }
1119 {
1120 InkAction* inky = ink_action_new( "NodeSmoothAction",
1121 _("Node Smooth"),
1122 _("Make selected nodes smooth"),
1123 "node_smooth",
1124 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1125 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1126 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1127 }
1129 {
1130 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1131 _("Node Symmetric"),
1132 _("Make selected nodes symmetric"),
1133 "node_symmetric",
1134 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1135 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1136 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1137 }
1139 {
1140 InkAction* inky = ink_action_new( "NodeLineAction",
1141 _("Node Line"),
1142 _("Make selected segments lines"),
1143 "node_line",
1144 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1145 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1146 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1147 }
1149 {
1150 InkAction* inky = ink_action_new( "NodeCurveAction",
1151 _("Node Curve"),
1152 _("Make selected segments curves"),
1153 "node_curve",
1154 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1155 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1156 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1157 }
1159 {
1160 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1161 _("Show Handles"),
1162 _("Show the Bezier handles of selected nodes"),
1163 "nodes_show_handles",
1164 Inkscape::ICON_SIZE_DECORATION );
1165 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1166 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1167 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1168 }
1170 {
1171 InkToggleAction* act = ink_toggle_action_new( "NodesShowHelperpath",
1172 _("Show Outline"),
1173 _("Show the outline of the path"),
1174 "nodes_show_helperpath",
1175 Inkscape::ICON_SIZE_DECORATION );
1176 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1177 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_helperpath), desktop );
1178 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_helperpath", 0 ) );
1179 }
1181 {
1182 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1183 _("Next path effect parameter"),
1184 _("Show next path effect parameter for editing"),
1185 "edit_next_parameter",
1186 Inkscape::ICON_SIZE_DECORATION );
1187 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1188 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1189 g_object_set_data( holder, "nodes_lpeedit", inky);
1190 }
1192 {
1193 InkAction* inky = ink_action_new( "ObjectEditClipPathAction",
1194 _("Edit clipping path"),
1195 _("Edit the clipping path of the object"),
1196 "nodeedit-clippath",
1197 Inkscape::ICON_SIZE_DECORATION );
1198 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_clippath), desktop );
1199 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1200 g_object_set_data( holder, "nodes_clippathedit", inky);
1201 }
1203 {
1204 InkAction* inky = ink_action_new( "ObjectEditMaskPathAction",
1205 _("Edit mask path"),
1206 _("Edit the mask of the object"),
1207 "nodeedit-mask",
1208 Inkscape::ICON_SIZE_DECORATION );
1209 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_maskpath), desktop );
1210 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1211 g_object_set_data( holder, "nodes_maskedit", inky);
1212 }
1214 /* X coord of selected node(s) */
1215 {
1216 EgeAdjustmentAction* eact = 0;
1217 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1218 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1219 eact = create_adjustment_action( "NodeXAction",
1220 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1221 "tools.nodes", "Xcoord", 0,
1222 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1223 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1224 labels, values, G_N_ELEMENTS(labels),
1225 sp_node_path_x_value_changed );
1226 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1227 g_object_set_data( holder, "nodes_x_action", eact );
1228 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1229 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1230 }
1232 /* Y coord of selected node(s) */
1233 {
1234 EgeAdjustmentAction* eact = 0;
1235 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1236 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1237 eact = create_adjustment_action( "NodeYAction",
1238 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1239 "tools.nodes", "Ycoord", 0,
1240 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1241 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1242 labels, values, G_N_ELEMENTS(labels),
1243 sp_node_path_y_value_changed );
1244 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1245 g_object_set_data( holder, "nodes_y_action", eact );
1246 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1247 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1248 }
1250 // add the units menu
1251 {
1252 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1253 gtk_action_group_add_action( mainActions, act );
1254 }
1257 sp_node_toolbox_sel_changed(sp_desktop_selection(desktop), holder);
1259 //watch selection
1260 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISNodeToolbox");
1262 sigc::connection *c_selection_changed =
1263 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
1264 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_changed), (GObject*)holder)));
1265 pool->add_connection ("selection-changed", c_selection_changed);
1267 sigc::connection *c_selection_modified =
1268 new sigc::connection (sp_desktop_selection (desktop)->connectModified
1269 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_sel_modified), (GObject*)holder)));
1270 pool->add_connection ("selection-modified", c_selection_modified);
1272 sigc::connection *c_subselection_changed =
1273 new sigc::connection (desktop->connectToolSubselectionChanged
1274 (sigc::bind (sigc::ptr_fun (sp_node_toolbox_coord_changed), (GObject*)holder)));
1275 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
1277 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (holder), pool);
1279 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1280 } // end of sp_node_toolbox_prep()
1283 //########################
1284 //## Zoom Toolbox ##
1285 //########################
1287 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1288 {
1289 // no custom GtkAction setup needed
1290 } // end of sp_zoom_toolbox_prep()
1292 void
1293 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1294 {
1295 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")));
1296 }
1299 void
1300 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1301 {
1302 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")));
1303 }
1305 void
1306 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1307 {
1308 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")));
1309 }
1311 static void
1312 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1313 {
1314 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1315 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1317 if (old_desktop) {
1318 GList *children, *iter;
1320 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1321 for ( iter = children ; iter ; iter = iter->next ) {
1322 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1323 }
1324 g_list_free(children);
1325 }
1327 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1329 if (desktop) {
1330 gtk_widget_set_sensitive(toolbox, TRUE);
1331 setup_func(toolbox, desktop);
1332 update_func(desktop, desktop->event_context, toolbox);
1333 *conn = desktop->connectEventContextChanged
1334 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1335 } else {
1336 gtk_widget_set_sensitive(toolbox, FALSE);
1337 }
1339 } // end of toolbox_set_desktop()
1342 static void
1343 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1344 {
1345 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
1346 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
1347 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
1348 // "toolbox.tools" was not set. Fallback to older value
1349 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
1351 // Copy the setting forwards
1352 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
1353 }
1354 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1356 for (int i = 0 ; tools[i].type_name ; i++ ) {
1357 GtkWidget *button =
1358 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
1359 SP_BUTTON_TYPE_TOGGLE,
1360 Inkscape::Verb::get(tools[i].verb),
1361 Inkscape::Verb::get(tools[i].doubleclick_verb),
1362 desktop,
1363 tooltips );
1365 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1366 (gpointer)button );
1367 }
1368 }
1371 static void
1372 update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
1373 {
1374 gchar const *const tname = ( eventcontext
1375 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1376 : NULL );
1377 for (int i = 0 ; tools[i].type_name ; i++ ) {
1378 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1379 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1380 }
1381 }
1383 static void
1384 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1385 {
1386 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1387 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1388 GtkUIManager* mgr = gtk_ui_manager_new();
1389 GError* errVal = 0;
1390 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1391 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1393 std::map<std::string, GtkWidget*> dataHolders;
1395 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1396 if ( aux_toolboxes[i].prep_func ) {
1397 // converted to GtkActions and UIManager
1399 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1400 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1401 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1402 dataHolders[aux_toolboxes[i].type_name] = kludge;
1403 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1404 } else {
1406 GtkWidget *sub_toolbox = 0;
1407 if (aux_toolboxes[i].create_func == NULL)
1408 sub_toolbox = sp_empty_toolbox_new(desktop);
1409 else {
1410 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1411 }
1413 gtk_size_group_add_widget( grouper, sub_toolbox );
1415 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1416 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1418 }
1419 }
1421 // Second pass to create toolbars *after* all GtkActions are created
1422 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1423 if ( aux_toolboxes[i].prep_func ) {
1424 // converted to GtkActions and UIManager
1426 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1428 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1429 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1431 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1432 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1433 g_free( tmp );
1434 tmp = 0;
1436 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1437 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1438 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1439 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1440 }
1441 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1444 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1446 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1447 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1448 swatch->setDesktop( desktop );
1449 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1450 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1451 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1452 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 );
1453 }
1455 gtk_widget_show_all( holder );
1456 sp_set_font_size_smaller( holder );
1458 gtk_size_group_add_widget( grouper, holder );
1460 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1461 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1462 }
1463 }
1465 g_object_unref( G_OBJECT(grouper) );
1466 }
1468 static void
1469 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1470 {
1471 gchar const *tname = ( eventcontext
1472 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1473 : NULL );
1474 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1475 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1476 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1477 gtk_widget_show_all(sub_toolbox);
1478 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1479 } else {
1480 gtk_widget_hide(sub_toolbox);
1481 }
1482 }
1483 }
1485 static void
1486 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1487 {
1488 gchar const * descr =
1489 "<ui>"
1490 " <toolbar name='CommandsToolbar'>"
1491 " <toolitem action='FileNew' />"
1492 " <toolitem action='FileOpen' />"
1493 " <toolitem action='FileSave' />"
1494 " <toolitem action='FilePrint' />"
1495 " <separator />"
1496 " <toolitem action='FileImport' />"
1497 " <toolitem action='FileExport' />"
1498 " <separator />"
1499 " <toolitem action='EditUndo' />"
1500 " <toolitem action='EditRedo' />"
1501 " <separator />"
1502 " <toolitem action='EditCopy' />"
1503 " <toolitem action='EditCut' />"
1504 " <toolitem action='EditPaste' />"
1505 " <separator />"
1506 " <toolitem action='ZoomSelection' />"
1507 " <toolitem action='ZoomDrawing' />"
1508 " <toolitem action='ZoomPage' />"
1509 " <separator />"
1510 " <toolitem action='EditDuplicate' />"
1511 " <toolitem action='EditClone' />"
1512 " <toolitem action='EditUnlinkClone' />"
1513 " <separator />"
1514 " <toolitem action='SelectionGroup' />"
1515 " <toolitem action='SelectionUnGroup' />"
1516 " <separator />"
1517 " <toolitem action='DialogFillStroke' />"
1518 " <toolitem action='DialogText' />"
1519 " <toolitem action='DialogXMLEditor' />"
1520 " <toolitem action='DialogAlignDistribute' />"
1521 " <separator />"
1522 " <toolitem action='DialogPreferences' />"
1523 " <toolitem action='DialogDocumentProperties' />"
1524 " </toolbar>"
1525 "</ui>";
1526 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1529 GtkUIManager* mgr = gtk_ui_manager_new();
1530 GError* errVal = 0;
1532 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1533 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1535 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1536 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1537 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1538 }
1539 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1540 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1541 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1544 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1545 }
1547 static void
1548 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1549 {
1550 }
1552 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1553 {
1554 gtk_widget_show(toolbox_toplevel);
1555 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1557 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1558 if (!shown_toolbox) {
1559 return;
1560 }
1561 gtk_widget_show(toolbox);
1563 gtk_widget_show_all(shown_toolbox);
1564 }
1566 void
1567 aux_toolbox_space(GtkWidget *tb, gint space)
1568 {
1569 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1570 }
1572 static GtkWidget *
1573 sp_empty_toolbox_new(SPDesktop *desktop)
1574 {
1575 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1576 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1577 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1579 gtk_widget_show_all(tbl);
1580 sp_set_font_size_smaller (tbl);
1582 return tbl;
1583 }
1585 // helper UI functions
1587 GtkWidget *
1588 sp_tb_spinbutton(
1589 gchar *label, gchar const *tooltip,
1590 gchar const *path, gchar const *data, gdouble def,
1591 GtkWidget *us,
1592 GtkWidget *tbl,
1593 gboolean altx, gchar const *altx_mark,
1594 gdouble lower, gdouble upper, gdouble step, gdouble page,
1595 void (*callback)(GtkAdjustment *, GtkWidget *),
1596 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1597 {
1598 GtkTooltips *tt = gtk_tooltips_new();
1600 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1602 GtkWidget *l = gtk_label_new(label);
1603 gtk_widget_show(l);
1604 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1605 gtk_container_add(GTK_CONTAINER(hb), l);
1607 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1608 lower, upper, step, page, page);
1609 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1610 if (us)
1611 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1613 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1614 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1615 if (altx)
1616 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1617 gtk_widget_set_size_request(sb,
1618 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1619 AUX_SPINBUTTON_HEIGHT);
1620 gtk_widget_show(sb);
1621 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1622 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1623 gtk_container_add(GTK_CONTAINER(hb), sb);
1624 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1626 return hb;
1627 }
1629 #define MODE_LABEL_WIDTH 70
1631 //########################
1632 //## Star ##
1633 //########################
1635 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1636 {
1637 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1639 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1640 // do not remember prefs if this call is initiated by an undo change, because undoing object
1641 // creation sets bogus values to its attributes before it is deleted
1642 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1643 }
1645 // quit if run by the attr_changed listener
1646 if (g_object_get_data( dataKludge, "freeze" )) {
1647 return;
1648 }
1650 // in turn, prevent listener from responding
1651 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1653 bool modmade = false;
1655 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1656 GSList const *items = selection->itemList();
1657 for (; items != NULL; items = items->next) {
1658 if (SP_IS_STAR((SPItem *) items->data)) {
1659 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1660 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1661 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1662 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1663 + M_PI / (gint)adj->value));
1664 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1665 modmade = true;
1666 }
1667 }
1668 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1669 _("Star: Change number of corners"));
1671 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1672 }
1674 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1675 {
1676 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1678 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1679 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1680 }
1682 // quit if run by the attr_changed listener
1683 if (g_object_get_data( dataKludge, "freeze" )) {
1684 return;
1685 }
1687 // in turn, prevent listener from responding
1688 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1690 bool modmade = false;
1691 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1692 GSList const *items = selection->itemList();
1693 for (; items != NULL; items = items->next) {
1694 if (SP_IS_STAR((SPItem *) items->data)) {
1695 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1697 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1698 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1699 if (r2 < r1) {
1700 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1701 } else {
1702 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1703 }
1705 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1706 modmade = true;
1707 }
1708 }
1710 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1711 _("Star: Change spoke ratio"));
1713 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1714 }
1716 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1717 {
1718 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1719 bool flat = ege_select_one_action_get_active( act ) == 0;
1721 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1722 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1723 flat ? "true" : "false" );
1724 }
1726 // quit if run by the attr_changed listener
1727 if (g_object_get_data( dataKludge, "freeze" )) {
1728 return;
1729 }
1731 // in turn, prevent listener from responding
1732 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1734 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1735 GSList const *items = selection->itemList();
1736 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1737 bool modmade = false;
1739 if ( prop_action ) {
1740 gtk_action_set_sensitive( prop_action, !flat );
1741 }
1743 for (; items != NULL; items = items->next) {
1744 if (SP_IS_STAR((SPItem *) items->data)) {
1745 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1746 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1747 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1748 modmade = true;
1749 }
1750 }
1752 if (modmade) {
1753 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1754 flat ? _("Make polygon") : _("Make star"));
1755 }
1757 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1758 }
1760 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1761 {
1762 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1764 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1765 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1766 }
1768 // quit if run by the attr_changed listener
1769 if (g_object_get_data( dataKludge, "freeze" )) {
1770 return;
1771 }
1773 // in turn, prevent listener from responding
1774 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1776 bool modmade = false;
1778 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1779 GSList const *items = selection->itemList();
1780 for (; items != NULL; items = items->next) {
1781 if (SP_IS_STAR((SPItem *) items->data)) {
1782 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1783 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1784 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1785 modmade = true;
1786 }
1787 }
1788 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1789 _("Star: Change rounding"));
1791 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1792 }
1794 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1795 {
1796 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1798 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1799 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1800 }
1802 // quit if run by the attr_changed listener
1803 if (g_object_get_data( dataKludge, "freeze" )) {
1804 return;
1805 }
1807 // in turn, prevent listener from responding
1808 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1810 bool modmade = false;
1812 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1813 GSList const *items = selection->itemList();
1814 for (; items != NULL; items = items->next) {
1815 if (SP_IS_STAR((SPItem *) items->data)) {
1816 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1817 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1818 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1819 modmade = true;
1820 }
1821 }
1822 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1823 _("Star: Change randomization"));
1825 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1826 }
1829 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1830 gchar const */*old_value*/, gchar const */*new_value*/,
1831 bool /*is_interactive*/, gpointer data)
1832 {
1833 GtkWidget *tbl = GTK_WIDGET(data);
1835 // quit if run by the _changed callbacks
1836 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1837 return;
1838 }
1840 // in turn, prevent callbacks from responding
1841 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1843 GtkAdjustment *adj = 0;
1845 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1846 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1848 if (!strcmp(name, "inkscape:randomized")) {
1849 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1850 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1851 } else if (!strcmp(name, "inkscape:rounded")) {
1852 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1853 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1854 } else if (!strcmp(name, "inkscape:flatsided")) {
1855 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1856 char const *flatsides = repr->attribute("inkscape:flatsided");
1857 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1858 if ( flatsides && !strcmp(flatsides,"false") ) {
1859 ege_select_one_action_set_active( flat_action, 1 );
1860 gtk_action_set_sensitive( prop_action, TRUE );
1861 } else {
1862 ege_select_one_action_set_active( flat_action, 0 );
1863 gtk_action_set_sensitive( prop_action, FALSE );
1864 }
1865 } else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) {
1866 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1867 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1868 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1869 if (r2 < r1) {
1870 gtk_adjustment_set_value(adj, r2/r1);
1871 } else {
1872 gtk_adjustment_set_value(adj, r1/r2);
1873 }
1874 } else if (!strcmp(name, "sodipodi:sides")) {
1875 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1876 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1877 }
1879 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1880 }
1883 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1884 {
1885 NULL, /* child_added */
1886 NULL, /* child_removed */
1887 star_tb_event_attr_changed,
1888 NULL, /* content_changed */
1889 NULL /* order_changed */
1890 };
1893 /**
1894 * \param selection Should not be NULL.
1895 */
1896 static void
1897 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1898 {
1899 int n_selected = 0;
1900 Inkscape::XML::Node *repr = NULL;
1902 purge_repr_listener( tbl, tbl );
1904 for (GSList const *items = selection->itemList();
1905 items != NULL;
1906 items = items->next)
1907 {
1908 if (SP_IS_STAR((SPItem *) items->data)) {
1909 n_selected++;
1910 repr = SP_OBJECT_REPR((SPItem *) items->data);
1911 }
1912 }
1914 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1916 if (n_selected == 0) {
1917 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1918 } else if (n_selected == 1) {
1919 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1921 if (repr) {
1922 g_object_set_data( tbl, "repr", repr );
1923 Inkscape::GC::anchor(repr);
1924 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1925 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1926 }
1927 } else {
1928 // FIXME: implement averaging of all parameters for multiple selected stars
1929 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1930 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1931 }
1932 }
1935 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
1936 {
1937 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1938 // callbacks to lump all the changes for all selected objects in one undo step
1940 GtkAdjustment *adj = 0;
1942 // fixme: make settable in prefs!
1943 gint mag = 5;
1944 gdouble prop = 0.5;
1945 gboolean flat = FALSE;
1946 gdouble randomized = 0;
1947 gdouble rounded = 0;
1949 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1950 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1952 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1953 gtk_action_set_sensitive( sb2, !flat );
1955 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1956 gtk_adjustment_set_value(adj, mag);
1957 gtk_adjustment_value_changed(adj);
1959 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1960 gtk_adjustment_set_value(adj, prop);
1961 gtk_adjustment_value_changed(adj);
1963 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1964 gtk_adjustment_set_value(adj, rounded);
1965 gtk_adjustment_value_changed(adj);
1967 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1968 gtk_adjustment_set_value(adj, randomized);
1969 gtk_adjustment_value_changed(adj);
1970 }
1973 void
1974 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1975 {
1976 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1977 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1978 GtkWidget *l = gtk_label_new(NULL);
1979 gtk_label_set_markup(GTK_LABEL(l), title);
1980 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1981 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1982 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1983 }
1986 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1987 {
1988 {
1989 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1990 ege_output_action_set_use_markup( act, TRUE );
1991 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1992 g_object_set_data( holder, "mode_action", act );
1993 }
1995 {
1996 EgeAdjustmentAction* eact = 0;
1997 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1998 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
2000 /* Flatsided checkbox */
2001 {
2002 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2004 GtkTreeIter iter;
2005 gtk_list_store_append( model, &iter );
2006 gtk_list_store_set( model, &iter,
2007 0, _("Polygon"),
2008 1, _("Regular polygon (with one handle) instead of a star"),
2009 2, "star_flat",
2010 -1 );
2012 gtk_list_store_append( model, &iter );
2013 gtk_list_store_set( model, &iter,
2014 0, _("Star"),
2015 1, _("Star instead of a regular polygon (with one handle)"),
2016 2, "star_angled",
2017 -1 );
2019 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
2020 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2021 g_object_set_data( holder, "flat_action", act );
2023 ege_select_one_action_set_appearance( act, "full" );
2024 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2025 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2026 ege_select_one_action_set_icon_column( act, 2 );
2027 ege_select_one_action_set_tooltip_column( act, 1 );
2029 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
2030 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
2031 }
2033 /* Magnitude */
2034 {
2035 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
2036 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
2037 eact = create_adjustment_action( "MagnitudeAction",
2038 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
2039 "tools.shapes.star", "magnitude", 3,
2040 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2041 3, 1024, 1, 5,
2042 labels, values, G_N_ELEMENTS(labels),
2043 sp_stb_magnitude_value_changed,
2044 1.0, 0 );
2045 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2046 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2047 }
2049 /* Spoke ratio */
2050 {
2051 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
2052 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
2053 eact = create_adjustment_action( "SpokeAction",
2054 _("Spoke ratio"), _("Spoke ratio:"),
2055 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
2056 // Base radius is the same for the closest handle.
2057 _("Base radius to tip radius ratio"),
2058 "tools.shapes.star", "proportion", 0.5,
2059 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2060 0.01, 1.0, 0.01, 0.1,
2061 labels, values, G_N_ELEMENTS(labels),
2062 sp_stb_proportion_value_changed );
2063 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2064 g_object_set_data( holder, "prop_action", eact );
2065 }
2067 if ( !isFlatSided ) {
2068 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2069 } else {
2070 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2071 }
2073 /* Roundedness */
2074 {
2075 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
2076 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
2077 eact = create_adjustment_action( "RoundednessAction",
2078 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
2079 "tools.shapes.star", "rounded", 0.0,
2080 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2081 -10.0, 10.0, 0.01, 0.1,
2082 labels, values, G_N_ELEMENTS(labels),
2083 sp_stb_rounded_value_changed );
2084 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2085 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2086 }
2088 /* Randomization */
2089 {
2090 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
2091 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
2092 eact = create_adjustment_action( "RandomizationAction",
2093 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
2094 "tools.shapes.star", "randomized", 0.0,
2095 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2096 -10.0, 10.0, 0.001, 0.01,
2097 labels, values, G_N_ELEMENTS(labels),
2098 sp_stb_randomized_value_changed, 0.1, 3 );
2099 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2100 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2101 }
2102 }
2104 {
2105 /* Reset */
2106 {
2107 GtkAction* act = gtk_action_new( "StarResetAction",
2108 _("Defaults"),
2109 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2110 GTK_STOCK_CLEAR );
2111 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
2112 gtk_action_group_add_action( mainActions, act );
2113 gtk_action_set_sensitive( act, TRUE );
2114 }
2115 }
2117 sigc::connection *connection = new sigc::connection(
2118 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
2119 );
2120 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2121 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2122 }
2125 //########################
2126 //## Rect ##
2127 //########################
2129 static void sp_rtb_sensitivize( GObject *tbl )
2130 {
2131 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
2132 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
2133 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
2135 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
2136 gtk_action_set_sensitive( not_rounded, FALSE );
2137 } else {
2138 gtk_action_set_sensitive( not_rounded, TRUE );
2139 }
2140 }
2143 static void
2144 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
2145 void (*setter)(SPRect *, gdouble))
2146 {
2147 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2149 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2150 SPUnit const *unit = tracker->getActiveUnit();
2152 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2153 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
2154 }
2156 // quit if run by the attr_changed listener
2157 if (g_object_get_data( tbl, "freeze" )) {
2158 return;
2159 }
2161 // in turn, prevent listener from responding
2162 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2164 bool modmade = false;
2165 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2166 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2167 if (SP_IS_RECT(items->data)) {
2168 if (adj->value != 0) {
2169 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2170 } else {
2171 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2172 }
2173 modmade = true;
2174 }
2175 }
2177 sp_rtb_sensitivize( tbl );
2179 if (modmade) {
2180 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2181 _("Change rectangle"));
2182 }
2184 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2185 }
2187 static void
2188 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2189 {
2190 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2191 }
2193 static void
2194 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2195 {
2196 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2197 }
2199 static void
2200 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2201 {
2202 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2203 }
2205 static void
2206 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2207 {
2208 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2209 }
2213 static void
2214 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2215 {
2216 GtkAdjustment *adj = 0;
2218 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2219 gtk_adjustment_set_value(adj, 0.0);
2220 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2221 gtk_adjustment_value_changed(adj);
2223 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2224 gtk_adjustment_set_value(adj, 0.0);
2225 gtk_adjustment_value_changed(adj);
2227 sp_rtb_sensitivize( obj );
2228 }
2230 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2231 gchar const */*old_value*/, gchar const */*new_value*/,
2232 bool /*is_interactive*/, gpointer data)
2233 {
2234 GObject *tbl = G_OBJECT(data);
2236 // quit if run by the _changed callbacks
2237 if (g_object_get_data( tbl, "freeze" )) {
2238 return;
2239 }
2241 // in turn, prevent callbacks from responding
2242 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2244 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2245 SPUnit const *unit = tracker->getActiveUnit();
2247 gpointer item = g_object_get_data( tbl, "item" );
2248 if (item && SP_IS_RECT(item)) {
2249 {
2250 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2251 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2252 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2253 }
2255 {
2256 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2257 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2258 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2259 }
2261 {
2262 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2263 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2264 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2265 }
2267 {
2268 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2269 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2270 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2271 }
2272 }
2274 sp_rtb_sensitivize( tbl );
2276 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2277 }
2280 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2281 NULL, /* child_added */
2282 NULL, /* child_removed */
2283 rect_tb_event_attr_changed,
2284 NULL, /* content_changed */
2285 NULL /* order_changed */
2286 };
2288 /**
2289 * \param selection should not be NULL.
2290 */
2291 static void
2292 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2293 {
2294 int n_selected = 0;
2295 Inkscape::XML::Node *repr = NULL;
2296 SPItem *item = NULL;
2298 if ( g_object_get_data( tbl, "repr" ) ) {
2299 g_object_set_data( tbl, "item", NULL );
2300 }
2301 purge_repr_listener( tbl, tbl );
2303 for (GSList const *items = selection->itemList();
2304 items != NULL;
2305 items = items->next) {
2306 if (SP_IS_RECT((SPItem *) items->data)) {
2307 n_selected++;
2308 item = (SPItem *) items->data;
2309 repr = SP_OBJECT_REPR(item);
2310 }
2311 }
2313 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2315 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2317 if (n_selected == 0) {
2318 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2320 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2321 gtk_action_set_sensitive(w, FALSE);
2322 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2323 gtk_action_set_sensitive(h, FALSE);
2325 } else if (n_selected == 1) {
2326 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2327 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2329 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2330 gtk_action_set_sensitive(w, TRUE);
2331 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2332 gtk_action_set_sensitive(h, TRUE);
2334 if (repr) {
2335 g_object_set_data( tbl, "repr", repr );
2336 g_object_set_data( tbl, "item", item );
2337 Inkscape::GC::anchor(repr);
2338 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2339 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2340 }
2341 } else {
2342 // FIXME: implement averaging of all parameters for multiple selected
2343 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2344 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2345 sp_rtb_sensitivize( tbl );
2346 }
2347 }
2350 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2351 {
2352 EgeAdjustmentAction* eact = 0;
2354 {
2355 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2356 ege_output_action_set_use_markup( act, TRUE );
2357 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2358 g_object_set_data( holder, "mode_action", act );
2359 }
2361 // rx/ry units menu: create
2362 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2363 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2364 // fixme: add % meaning per cent of the width/height
2365 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2366 g_object_set_data( holder, "tracker", tracker );
2368 /* W */
2369 {
2370 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2371 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2372 eact = create_adjustment_action( "RectWidthAction",
2373 _("Width"), _("W:"), _("Width of rectangle"),
2374 "tools.shapes.rect", "width", 0,
2375 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2376 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2377 labels, values, G_N_ELEMENTS(labels),
2378 sp_rtb_width_value_changed );
2379 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2380 g_object_set_data( holder, "width_action", eact );
2381 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2382 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2383 }
2385 /* H */
2386 {
2387 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2388 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2389 eact = create_adjustment_action( "RectHeightAction",
2390 _("Height"), _("H:"), _("Height of rectangle"),
2391 "tools.shapes.rect", "height", 0,
2392 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2393 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2394 labels, values, G_N_ELEMENTS(labels),
2395 sp_rtb_height_value_changed );
2396 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2397 g_object_set_data( holder, "height_action", eact );
2398 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2399 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2400 }
2402 /* rx */
2403 {
2404 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2405 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2406 eact = create_adjustment_action( "RadiusXAction",
2407 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2408 "tools.shapes.rect", "rx", 0,
2409 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2410 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2411 labels, values, G_N_ELEMENTS(labels),
2412 sp_rtb_rx_value_changed);
2413 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2414 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2415 }
2417 /* ry */
2418 {
2419 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2420 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2421 eact = create_adjustment_action( "RadiusYAction",
2422 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2423 "tools.shapes.rect", "ry", 0,
2424 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2425 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2426 labels, values, G_N_ELEMENTS(labels),
2427 sp_rtb_ry_value_changed);
2428 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2429 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2430 }
2432 // add the units menu
2433 {
2434 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2435 gtk_action_group_add_action( mainActions, act );
2436 }
2438 /* Reset */
2439 {
2440 InkAction* inky = ink_action_new( "RectResetAction",
2441 _("Not rounded"),
2442 _("Make corners sharp"),
2443 "squared_corner",
2444 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2445 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2446 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2447 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2448 g_object_set_data( holder, "not_rounded", inky );
2449 }
2451 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2452 sp_rtb_sensitivize( holder );
2454 sigc::connection *connection = new sigc::connection(
2455 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2456 );
2457 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2458 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2459 }
2461 //########################
2462 //## 3D Box ##
2463 //########################
2465 // normalize angle so that it lies in the interval [0,360]
2466 static double box3d_normalize_angle (double a) {
2467 double angle = a + ((int) (a/360.0))*360;
2468 if (angle < 0) {
2469 angle += 360.0;
2470 }
2471 return angle;
2472 }
2474 static void
2475 box3d_set_button_and_adjustment(Persp3D *persp, Proj::Axis axis,
2476 GtkAdjustment *adj, GtkAction *act, GtkToggleAction *tact) {
2477 // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
2478 // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
2479 // are reset).
2480 bool is_infinite = !persp3d_VP_is_finite(persp, axis);
2482 if (is_infinite) {
2483 gtk_toggle_action_set_active(tact, TRUE);
2484 gtk_action_set_sensitive(act, TRUE);
2486 double angle = persp3d_get_infinite_angle(persp, axis);
2487 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
2488 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
2489 }
2490 } else {
2491 gtk_toggle_action_set_active(tact, FALSE);
2492 gtk_action_set_sensitive(act, FALSE);
2493 }
2494 }
2496 static void
2497 box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) {
2498 if (!persp_repr) {
2499 g_print ("No perspective given to box3d_resync_toolbar().\n");
2500 return;
2501 }
2503 GtkWidget *tbl = GTK_WIDGET(data);
2504 GtkAdjustment *adj = 0;
2505 GtkAction *act = 0;
2506 GtkToggleAction *tact = 0;
2507 Persp3D *persp = persp3d_get_from_repr(persp_repr);
2508 {
2509 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
2510 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
2511 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action;
2513 box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact);
2514 }
2515 {
2516 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_y"));
2517 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action"));
2518 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action;
2520 box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact);
2521 }
2522 {
2523 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_z"));
2524 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action"));
2525 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action;
2527 box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact);
2528 }
2529 }
2531 static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2532 gchar const */*old_value*/, gchar const */*new_value*/,
2533 bool /*is_interactive*/, gpointer data)
2534 {
2535 GtkWidget *tbl = GTK_WIDGET(data);
2537 // quit if run by the attr_changed listener
2538 // note: it used to work without the differently called freeze_ attributes (here and in
2539 // box3d_angle_value_changed()) but I now it doesn't so I'm leaving them in for now
2540 if (g_object_get_data(G_OBJECT(tbl), "freeze_angle")) {
2541 return;
2542 }
2544 // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling
2545 // sp_document_maybe_done() when the document is undo insensitive)
2546 g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(TRUE));
2548 // TODO: Only update the appropriate part of the toolbar
2549 // if (!strcmp(name, "inkscape:vp_z")) {
2550 box3d_resync_toolbar(repr, G_OBJECT(tbl));
2551 // }
2553 Persp3D *persp = persp3d_get_from_repr(repr);
2554 persp3d_update_box_reprs(persp);
2556 g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(FALSE));
2557 }
2559 static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
2560 {
2561 NULL, /* child_added */
2562 NULL, /* child_removed */
2563 box3d_persp_tb_event_attr_changed,
2564 NULL, /* content_changed */
2565 NULL /* order_changed */
2566 };
2568 /**
2569 * \param selection Should not be NULL.
2570 */
2571 // FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
2572 // Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
2573 static void
2574 box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2575 {
2576 // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
2577 // disable the angle entry fields for this direction (otherwise entering a value in them should only
2578 // update the perspectives with infinite VPs and leave the other ones untouched).
2580 Inkscape::XML::Node *persp_repr = NULL;
2581 purge_repr_listener(tbl, tbl);
2583 SPItem *item = selection->singleItem();
2584 if (item && SP_IS_BOX3D(item)) {
2585 // FIXME: Also deal with multiple selected boxes
2586 SPBox3D *box = SP_BOX3D(item);
2587 Persp3D *persp = box3d_get_perspective(box);
2588 persp_repr = SP_OBJECT_REPR(persp);
2589 if (persp_repr) {
2590 g_object_set_data(tbl, "repr", persp_repr);
2591 Inkscape::GC::anchor(persp_repr);
2592 sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl);
2593 sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
2594 }
2596 inkscape_active_document()->current_persp3d = persp3d_get_from_repr(persp_repr);
2597 prefs_set_string_attribute("tools.shapes.3dbox", "persp", persp_repr->attribute("id"));
2599 box3d_resync_toolbar(persp_repr, tbl);
2600 }
2601 }
2603 static void
2604 box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis)
2605 {
2606 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2607 SPDocument *document = sp_desktop_document(desktop);
2609 // quit if run by the attr_changed listener
2610 // note: it used to work without the differently called freeze_ attributes (here and in
2611 // box3d_persp_tb_event_attr_changed()) but I now it doesn't so I'm leaving them in for now
2612 if (g_object_get_data( dataKludge, "freeze_attr" )) {
2613 return;
2614 }
2616 // in turn, prevent listener from responding
2617 g_object_set_data(dataKludge, "freeze_angle", GINT_TO_POINTER(TRUE));
2619 //Persp3D *persp = document->current_persp3d;
2620 std::list<Persp3D *> sel_persps = sp_desktop_selection(desktop)->perspList();
2621 if (sel_persps.empty()) {
2622 // this can happen when the document is created; we silently ignore it
2623 return;
2624 }
2625 Persp3D *persp = sel_persps.front();
2627 persp->tmat.set_infinite_direction (axis, adj->value);
2628 SP_OBJECT(persp)->updateRepr();
2630 // TODO: use the correct axis here, too
2631 sp_document_maybe_done(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)"));
2633 g_object_set_data( dataKludge, "freeze_angle", GINT_TO_POINTER(FALSE) );
2634 }
2637 static void
2638 box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2639 {
2640 box3d_angle_value_changed(adj, dataKludge, Proj::X);
2641 }
2643 static void
2644 box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2645 {
2646 box3d_angle_value_changed(adj, dataKludge, Proj::Y);
2647 }
2649 static void
2650 box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2651 {
2652 box3d_angle_value_changed(adj, dataKludge, Proj::Z);
2653 }
2656 static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction */*box3d_angle*/, Proj::Axis axis )
2657 {
2658 // TODO: Take all selected perspectives into account
2659 std::list<Persp3D *> sel_persps = sp_desktop_selection(inkscape_active_desktop())->perspList();
2660 if (sel_persps.empty()) {
2661 // this can happen when the document is created; we silently ignore it
2662 return;
2663 }
2664 Persp3D *persp = sel_persps.front();
2666 bool set_infinite = gtk_toggle_action_get_active(act);
2667 persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
2668 }
2670 static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2671 {
2672 box3d_vp_state_changed(act, box3d_angle, Proj::X);
2673 }
2675 static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2676 {
2677 box3d_vp_state_changed(act, box3d_angle, Proj::Y);
2678 }
2680 static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2681 {
2682 box3d_vp_state_changed(act, box3d_angle, Proj::Z);
2683 }
2685 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2686 {
2687 EgeAdjustmentAction* eact = 0;
2688 SPDocument *document = sp_desktop_document (desktop);
2689 Persp3D *persp = document->current_persp3d;
2691 EgeAdjustmentAction* box3d_angle_x = 0;
2692 EgeAdjustmentAction* box3d_angle_y = 0;
2693 EgeAdjustmentAction* box3d_angle_z = 0;
2695 /* Angle X */
2696 {
2697 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2698 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2699 eact = create_adjustment_action( "3DBoxAngleXAction",
2700 _("Angle in X direction"), _("Angle X:"),
2701 // Translators: PL is short for 'perspective line'
2702 _("Angle of PLs in X direction"),
2703 "tools.shapes.3dbox", "box3d_angle_x", 30,
2704 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
2705 -360.0, 360.0, 1.0, 10.0,
2706 labels, values, G_N_ELEMENTS(labels),
2707 box3d_angle_x_value_changed );
2708 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2709 g_object_set_data( holder, "box3d_angle_x_action", eact );
2710 box3d_angle_x = eact;
2711 }
2713 if (!persp3d_VP_is_finite(persp, Proj::X)) {
2714 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2715 } else {
2716 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2717 }
2720 /* VP X state */
2721 {
2722 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction",
2723 // Translators: VP is short for 'vanishing point'
2724 _("State of VP in X direction"),
2725 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2726 "toggle_vp_x",
2727 Inkscape::ICON_SIZE_DECORATION );
2728 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2729 g_object_set_data( holder, "box3d_vp_x_state_action", act );
2730 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x );
2731 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
2732 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
2733 }
2735 /* Angle Y */
2736 {
2737 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2738 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2739 eact = create_adjustment_action( "3DBoxAngleYAction",
2740 _("Angle in Y direction"), _("Angle Y:"),
2741 // Translators: PL is short for 'perspective line'
2742 _("Angle of PLs in Y direction"),
2743 "tools.shapes.3dbox", "box3d_angle_y", 30,
2744 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2745 -360.0, 360.0, 1.0, 10.0,
2746 labels, values, G_N_ELEMENTS(labels),
2747 box3d_angle_y_value_changed );
2748 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2749 g_object_set_data( holder, "box3d_angle_y_action", eact );
2750 box3d_angle_y = eact;
2751 }
2753 if (!persp3d_VP_is_finite(persp, Proj::Y)) {
2754 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2755 } else {
2756 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2757 }
2759 /* VP Y state */
2760 {
2761 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction",
2762 // Translators: VP is short for 'vanishing point'
2763 _("State of VP in Y direction"),
2764 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2765 "toggle_vp_y",
2766 Inkscape::ICON_SIZE_DECORATION );
2767 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2768 g_object_set_data( holder, "box3d_vp_y_state_action", act );
2769 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y );
2770 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
2771 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
2772 }
2774 /* Angle Z */
2775 {
2776 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2777 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2778 eact = create_adjustment_action( "3DBoxAngleZAction",
2779 _("Angle in Z direction"), _("Angle Z:"),
2780 // Translators: PL is short for 'perspective line'
2781 _("Angle of PLs in Z direction"),
2782 "tools.shapes.3dbox", "box3d_angle_z", 30,
2783 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2784 -360.0, 360.0, 1.0, 10.0,
2785 labels, values, G_N_ELEMENTS(labels),
2786 box3d_angle_z_value_changed );
2787 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2788 g_object_set_data( holder, "box3d_angle_z_action", eact );
2789 box3d_angle_z = eact;
2790 }
2792 if (!persp3d_VP_is_finite(persp, Proj::Z)) {
2793 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2794 } else {
2795 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2796 }
2798 /* VP Z state */
2799 {
2800 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction",
2801 // Translators: VP is short for 'vanishing point'
2802 _("State of VP in Z direction"),
2803 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
2804 "toggle_vp_z",
2805 Inkscape::ICON_SIZE_DECORATION );
2806 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2807 g_object_set_data( holder, "box3d_vp_z_state_action", act );
2808 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z );
2809 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
2810 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
2811 }
2813 sigc::connection *connection = new sigc::connection(
2814 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
2815 );
2816 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
2817 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
2818 }
2820 //########################
2821 //## Spiral ##
2822 //########################
2824 static void
2825 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2826 {
2827 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2829 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2830 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2831 }
2833 // quit if run by the attr_changed listener
2834 if (g_object_get_data( tbl, "freeze" )) {
2835 return;
2836 }
2838 // in turn, prevent listener from responding
2839 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2841 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2843 bool modmade = false;
2844 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2845 items != NULL;
2846 items = items->next)
2847 {
2848 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2849 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2850 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2851 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2852 modmade = true;
2853 }
2854 }
2856 g_free(namespaced_name);
2858 if (modmade) {
2859 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2860 _("Change spiral"));
2861 }
2863 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2864 }
2866 static void
2867 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2868 {
2869 sp_spl_tb_value_changed(adj, tbl, "revolution");
2870 }
2872 static void
2873 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2874 {
2875 sp_spl_tb_value_changed(adj, tbl, "expansion");
2876 }
2878 static void
2879 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2880 {
2881 sp_spl_tb_value_changed(adj, tbl, "t0");
2882 }
2884 static void
2885 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
2886 {
2887 GtkWidget *tbl = GTK_WIDGET(obj);
2889 GtkAdjustment *adj;
2891 // fixme: make settable
2892 gdouble rev = 5;
2893 gdouble exp = 1.0;
2894 gdouble t0 = 0.0;
2896 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2897 gtk_adjustment_set_value(adj, rev);
2898 gtk_adjustment_value_changed(adj);
2900 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2901 gtk_adjustment_set_value(adj, exp);
2902 gtk_adjustment_value_changed(adj);
2904 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2905 gtk_adjustment_set_value(adj, t0);
2906 gtk_adjustment_value_changed(adj);
2908 spinbutton_defocus(GTK_OBJECT(tbl));
2909 }
2912 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2913 gchar const */*old_value*/, gchar const */*new_value*/,
2914 bool /*is_interactive*/, gpointer data)
2915 {
2916 GtkWidget *tbl = GTK_WIDGET(data);
2918 // quit if run by the _changed callbacks
2919 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2920 return;
2921 }
2923 // in turn, prevent callbacks from responding
2924 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2926 GtkAdjustment *adj;
2927 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2928 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2930 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2931 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2933 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2934 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2936 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2937 }
2940 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2941 NULL, /* child_added */
2942 NULL, /* child_removed */
2943 spiral_tb_event_attr_changed,
2944 NULL, /* content_changed */
2945 NULL /* order_changed */
2946 };
2948 static void
2949 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2950 {
2951 int n_selected = 0;
2952 Inkscape::XML::Node *repr = NULL;
2954 purge_repr_listener( tbl, tbl );
2956 for (GSList const *items = selection->itemList();
2957 items != NULL;
2958 items = items->next)
2959 {
2960 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2961 n_selected++;
2962 repr = SP_OBJECT_REPR((SPItem *) items->data);
2963 }
2964 }
2966 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2968 if (n_selected == 0) {
2969 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2970 } else if (n_selected == 1) {
2971 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2973 if (repr) {
2974 g_object_set_data( tbl, "repr", repr );
2975 Inkscape::GC::anchor(repr);
2976 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2977 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2978 }
2979 } else {
2980 // FIXME: implement averaging of all parameters for multiple selected
2981 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2982 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2983 }
2984 }
2987 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2988 {
2989 EgeAdjustmentAction* eact = 0;
2991 {
2992 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2993 ege_output_action_set_use_markup( act, TRUE );
2994 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2995 g_object_set_data( holder, "mode_action", act );
2996 }
2998 /* Revolution */
2999 {
3000 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
3001 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
3002 eact = create_adjustment_action( "SpiralRevolutionAction",
3003 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
3004 "tools.shapes.spiral", "revolution", 3.0,
3005 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
3006 0.01, 1024.0, 0.1, 1.0,
3007 labels, values, G_N_ELEMENTS(labels),
3008 sp_spl_tb_revolution_value_changed, 1, 2);
3009 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3010 }
3012 /* Expansion */
3013 {
3014 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
3015 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
3016 eact = create_adjustment_action( "SpiralExpansionAction",
3017 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
3018 "tools.shapes.spiral", "expansion", 1.0,
3019 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3020 0.0, 1000.0, 0.01, 1.0,
3021 labels, values, G_N_ELEMENTS(labels),
3022 sp_spl_tb_expansion_value_changed);
3023 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3024 }
3026 /* T0 */
3027 {
3028 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
3029 gdouble values[] = {0, 0.5, 0.9};
3030 eact = create_adjustment_action( "SpiralT0Action",
3031 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
3032 "tools.shapes.spiral", "t0", 0.0,
3033 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3034 0.0, 0.999, 0.01, 1.0,
3035 labels, values, G_N_ELEMENTS(labels),
3036 sp_spl_tb_t0_value_changed);
3037 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3038 }
3040 /* Reset */
3041 {
3042 InkAction* inky = ink_action_new( "SpiralResetAction",
3043 _("Defaults"),
3044 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
3045 GTK_STOCK_CLEAR,
3046 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3047 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
3048 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3049 }
3052 sigc::connection *connection = new sigc::connection(
3053 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
3054 );
3055 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3056 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3057 }
3059 //########################
3060 //## Pen/Pencil ##
3061 //########################
3064 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
3065 {
3066 // Put stuff here
3067 }
3069 static void sp_pencil_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
3070 {
3071 // Put stuff here
3072 }
3074 //########################
3075 //## Tweak ##
3076 //########################
3078 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3079 {
3080 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
3081 }
3083 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3084 {
3085 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
3086 }
3088 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3089 {
3090 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3091 }
3093 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
3094 {
3095 int mode = ege_select_one_action_get_active( act );
3096 prefs_set_int_attribute("tools.tweak", "mode", mode);
3098 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
3099 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
3100 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
3101 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
3102 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
3103 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
3104 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
3105 if (doh) gtk_action_set_sensitive (doh, TRUE);
3106 if (dos) gtk_action_set_sensitive (dos, TRUE);
3107 if (dol) gtk_action_set_sensitive (dol, TRUE);
3108 if (doo) gtk_action_set_sensitive (doo, TRUE);
3109 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
3110 if (fid) gtk_action_set_sensitive (fid, FALSE);
3111 } else {
3112 if (doh) gtk_action_set_sensitive (doh, FALSE);
3113 if (dos) gtk_action_set_sensitive (dos, FALSE);
3114 if (dol) gtk_action_set_sensitive (dol, FALSE);
3115 if (doo) gtk_action_set_sensitive (doo, FALSE);
3116 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
3117 if (fid) gtk_action_set_sensitive (fid, TRUE);
3118 }
3119 }
3121 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3122 {
3123 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
3124 }
3126 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
3127 bool show = gtk_toggle_action_get_active( act );
3128 prefs_set_int_attribute ("tools.tweak", "doh", show ? 1 : 0);
3129 }
3130 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
3131 bool show = gtk_toggle_action_get_active( act );
3132 prefs_set_int_attribute ("tools.tweak", "dos", show ? 1 : 0);
3133 }
3134 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
3135 bool show = gtk_toggle_action_get_active( act );
3136 prefs_set_int_attribute ("tools.tweak", "dol", show ? 1 : 0);
3137 }
3138 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
3139 bool show = gtk_toggle_action_get_active( act );
3140 prefs_set_int_attribute ("tools.tweak", "doo", show ? 1 : 0);
3141 }
3143 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3144 {
3145 {
3146 /* Width */
3147 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
3148 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3149 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
3150 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
3151 "tools.tweak", "width", 15,
3152 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
3153 1, 100, 1.0, 10.0,
3154 labels, values, G_N_ELEMENTS(labels),
3155 sp_tweak_width_value_changed, 0.01, 0, 100 );
3156 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3157 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3158 }
3161 {
3162 /* Force */
3163 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
3164 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
3165 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
3166 _("Force"), _("Force:"), _("The force of the tweak action"),
3167 "tools.tweak", "force", 20,
3168 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
3169 1, 100, 1.0, 10.0,
3170 labels, values, G_N_ELEMENTS(labels),
3171 sp_tweak_force_value_changed, 0.01, 0, 100 );
3172 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3173 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3174 }
3176 /* Mode */
3177 {
3178 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3180 GtkTreeIter iter;
3181 gtk_list_store_append( model, &iter );
3182 gtk_list_store_set( model, &iter,
3183 0, _("Push mode"),
3184 1, _("Push parts of paths in any direction"),
3185 2, "tweak_push_mode",
3186 -1 );
3188 gtk_list_store_append( model, &iter );
3189 gtk_list_store_set( model, &iter,
3190 0, _("Shrink mode"),
3191 1, _("Shrink (inset) parts of paths"),
3192 2, "tweak_shrink_mode",
3193 -1 );
3195 gtk_list_store_append( model, &iter );
3196 gtk_list_store_set( model, &iter,
3197 0, _("Grow mode"),
3198 1, _("Grow (outset) parts of paths"),
3199 2, "tweak_grow_mode",
3200 -1 );
3202 gtk_list_store_append( model, &iter );
3203 gtk_list_store_set( model, &iter,
3204 0, _("Attract mode"),
3205 1, _("Attract parts of paths towards cursor"),
3206 2, "tweak_attract_mode",
3207 -1 );
3209 gtk_list_store_append( model, &iter );
3210 gtk_list_store_set( model, &iter,
3211 0, _("Repel mode"),
3212 1, _("Repel parts of paths from cursor"),
3213 2, "tweak_repel_mode",
3214 -1 );
3216 gtk_list_store_append( model, &iter );
3217 gtk_list_store_set( model, &iter,
3218 0, _("Roughen mode"),
3219 1, _("Roughen parts of paths"),
3220 2, "tweak_roughen_mode",
3221 -1 );
3223 gtk_list_store_append( model, &iter );
3224 gtk_list_store_set( model, &iter,
3225 0, _("Color paint mode"),
3226 1, _("Paint the tool's color upon selected objects"),
3227 2, "tweak_colorpaint_mode",
3228 -1 );
3230 gtk_list_store_append( model, &iter );
3231 gtk_list_store_set( model, &iter,
3232 0, _("Color jitter mode"),
3233 1, _("Jitter the colors of selected objects"),
3234 2, "tweak_colorjitter_mode",
3235 -1 );
3237 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
3238 g_object_set( act, "short_label", _("Mode:"), NULL );
3239 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3240 g_object_set_data( holder, "mode_action", act );
3242 ege_select_one_action_set_appearance( act, "full" );
3243 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3244 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3245 ege_select_one_action_set_icon_column( act, 2 );
3246 ege_select_one_action_set_tooltip_column( act, 1 );
3248 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3249 ege_select_one_action_set_active( act, mode );
3250 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3252 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3253 }
3255 guint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3257 {
3258 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3259 ege_output_action_set_use_markup( act, TRUE );
3260 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3261 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3262 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3263 g_object_set_data( holder, "tweak_channels_label", act);
3264 }
3266 {
3267 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3268 _("Hue"),
3269 _("In color mode, act on objects' hue"),
3270 NULL,
3271 Inkscape::ICON_SIZE_DECORATION );
3272 g_object_set( act, "short_label", _("H"), NULL );
3273 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3274 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3275 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doh", 1 ) );
3276 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3277 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3278 g_object_set_data( holder, "tweak_doh", act);
3279 }
3280 {
3281 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3282 _("Saturation"),
3283 _("In color mode, act on objects' saturation"),
3284 NULL,
3285 Inkscape::ICON_SIZE_DECORATION );
3286 g_object_set( act, "short_label", _("S"), NULL );
3287 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3288 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3289 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dos", 1 ) );
3290 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3291 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3292 g_object_set_data( holder, "tweak_dos", act );
3293 }
3294 {
3295 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3296 _("Lightness"),
3297 _("In color mode, act on objects' lightness"),
3298 NULL,
3299 Inkscape::ICON_SIZE_DECORATION );
3300 g_object_set( act, "short_label", _("L"), NULL );
3301 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3302 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3303 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dol", 1 ) );
3304 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3305 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3306 g_object_set_data( holder, "tweak_dol", act );
3307 }
3308 {
3309 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3310 _("Opacity"),
3311 _("In color mode, act on objects' opacity"),
3312 NULL,
3313 Inkscape::ICON_SIZE_DECORATION );
3314 g_object_set( act, "short_label", _("O"), NULL );
3315 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3316 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3317 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doo", 1 ) );
3318 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3319 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3320 g_object_set_data( holder, "tweak_doo", act );
3321 }
3323 { /* Fidelity */
3324 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3325 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3326 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3327 _("Fidelity"), _("Fidelity:"),
3328 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3329 "tools.tweak", "fidelity", 50,
3330 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3331 1, 100, 1.0, 10.0,
3332 labels, values, G_N_ELEMENTS(labels),
3333 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3334 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3335 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3336 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3337 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3338 g_object_set_data( holder, "tweak_fidelity", eact );
3339 }
3342 /* Use Pressure button */
3343 {
3344 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3345 _("Pressure"),
3346 _("Use the pressure of the input device to alter the force of tweak action"),
3347 "use_pressure",
3348 Inkscape::ICON_SIZE_DECORATION );
3349 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3350 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3351 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
3352 }
3354 }
3357 //########################
3358 //## Calligraphy ##
3359 //########################
3360 static void update_presets_list(GObject *dataKludge ){
3361 EgeSelectOneAction *sel = static_cast<EgeSelectOneAction *>(g_object_get_data(dataKludge, "profile_selector"));
3362 if (sel) {
3363 ege_select_one_action_set_active(sel, 0 );
3364 }
3365 }
3367 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
3368 {
3369 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
3370 update_presets_list(tbl);
3371 }
3373 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
3374 {
3375 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
3376 update_presets_list(tbl);
3377 }
3379 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
3380 {
3381 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
3382 update_presets_list(tbl);
3383 }
3385 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
3386 {
3387 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
3388 update_presets_list(tbl);
3389 }
3391 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
3392 {
3393 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
3394 update_presets_list(tbl);
3395 }
3397 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
3398 {
3399 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
3400 update_presets_list(tbl);
3401 }
3403 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
3404 {
3405 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
3406 update_presets_list(tbl);
3407 }
3409 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
3410 {
3411 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
3412 update_presets_list(tbl);
3413 }
3415 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, GObject* tbl )
3416 {
3417 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3418 update_presets_list(tbl);
3419 }
3421 static void sp_ddc_trace_background_changed( GtkToggleAction *act, GObject* tbl )
3422 {
3423 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
3424 update_presets_list(tbl);
3425 }
3427 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GObject* tbl )
3428 {
3429 GtkAction * calligraphy_angle = static_cast<GtkAction *> (g_object_get_data(tbl,"angle"));
3430 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3431 update_presets_list(tbl);
3432 if (calligraphy_angle )
3433 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
3434 }
3437 #define PROFILE_FLOAT_SIZE 7
3438 #define PROFILE_INT_SIZE 4
3439 struct ProfileFloatElement {
3440 char const *name;
3441 double def;
3442 double min;
3443 double max;
3444 };
3445 struct ProfileIntElement {
3446 char const *name;
3447 int def;
3448 int min;
3449 int max;
3450 };
3454 static ProfileFloatElement f_profile[PROFILE_FLOAT_SIZE] = {
3455 {"mass",0.02, 0.0, 1.0},
3456 {"wiggle",0.0, 0.0, 1.0},
3457 {"angle",30.0, -90.0, 90.0},
3458 {"thinning",0.1, -1.0, 1.0},
3459 {"tremor",0.0, 0.0, 1.0},
3460 {"flatness",0.9, 0.0, 1.0},
3461 {"cap_rounding",0.0, 0.0, 5.0}
3462 };
3463 static ProfileIntElement i_profile[PROFILE_INT_SIZE] = {
3464 {"width",15, 1, 100},
3465 {"usepressure",1,0,1},
3466 {"tracebackground",0,0,1},
3467 {"usetilt",1,0,1},
3468 };
3472 static void sp_dcc_save_profile( GtkWidget */*widget*/, GObject *dataKludge ){
3473 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
3474 if (! desktop) return;
3476 Inkscape::UI::Dialogs::CalligraphicProfileDialog::show(desktop);
3477 if ( ! Inkscape::UI::Dialogs::CalligraphicProfileDialog::applied()) return;
3478 Glib::ustring profile_name = Inkscape::UI::Dialogs::CalligraphicProfileDialog::getProfileName();
3480 unsigned int new_index = pref_path_number_of_children("tools.calligraphic.preset") +1;
3481 gchar *profile_id = g_strdup_printf("dcc%d", new_index);
3482 gchar *pref_path = create_pref("tools.calligraphic.preset",profile_id);
3484 for (unsigned i = 0; i < PROFILE_FLOAT_SIZE; ++i) {
3485 ProfileFloatElement const &pe = f_profile[i];
3486 double v = prefs_get_double_attribute_limited("tools.calligraphic",pe.name, pe.def, pe.min, pe.max);
3487 prefs_set_double_attribute(pref_path,pe.name,v);
3488 }
3489 for (unsigned i = 0; i < PROFILE_INT_SIZE; ++i) {
3490 ProfileIntElement const &pe = i_profile[i];
3491 int v = prefs_get_int_attribute_limited("tools.calligraphic",pe.name, pe.def,pe.min, pe.max);
3492 prefs_set_int_attribute(pref_path,pe.name,v);
3493 }
3494 prefs_set_string_attribute(pref_path,"name",profile_name.c_str());
3496 EgeSelectOneAction* selector = static_cast<EgeSelectOneAction *>(g_object_get_data(dataKludge, "profile_selector"));
3497 GtkListStore* model = GTK_LIST_STORE(ege_select_one_action_get_model(selector));
3498 GtkTreeIter iter;
3499 gtk_list_store_append( model, &iter );
3500 gtk_list_store_set( model, &iter, 0, profile_name.c_str(), 1, new_index, -1 );
3502 free(profile_id);
3503 free(pref_path);
3505 ege_select_one_action_set_active(selector, new_index);
3506 }
3509 static void sp_ddc_change_profile(EgeSelectOneAction* act, GObject *dataKludge) {
3511 gint preset_index = ege_select_one_action_get_active( act );
3512 gchar *profile_name = get_pref_nth_child("tools.calligraphic.preset", preset_index);
3514 if ( profile_name) {
3515 g_object_set_data(dataKludge, "profile_selector",NULL); //temporary hides the selector so no one will updadte it
3516 for (unsigned i = 0; i < PROFILE_FLOAT_SIZE; ++i) {
3517 ProfileFloatElement const &pe = f_profile[i];
3518 double v = prefs_get_double_attribute_limited(profile_name, pe.name, pe.def, pe.min, pe.max);
3519 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, pe.name));
3520 if ( adj ) {
3521 gtk_adjustment_set_value(adj, v);
3522 }
3523 }
3524 for (unsigned i = 0; i < PROFILE_INT_SIZE; ++i) {
3525 ProfileIntElement const &pe = i_profile[i];
3526 int v = prefs_get_int_attribute_limited(profile_name, pe.name, pe.def, pe.min, pe.max);
3527 GtkToggleAction* toggle = static_cast<GtkToggleAction *>(g_object_get_data(dataKludge, pe.name));
3528 if ( toggle ) {
3529 gtk_toggle_action_set_active(toggle, v);
3530 } else printf("No toggle");
3531 }
3532 free(profile_name);
3533 g_object_set_data(dataKludge, "profile_selector",act); //restore selector visibility
3534 }
3536 }
3539 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3540 {
3541 {
3542 EgeAdjustmentAction* calligraphy_angle = 0;
3544 {
3545 /* Width */
3546 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
3547 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3548 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
3549 _("Pen Width"), _("Width:"),
3550 _("The width of the calligraphic pen (relative to the visible canvas area)"),
3551 "tools.calligraphic", "width", 15,
3552 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
3553 1, 100, 1.0, 10.0,
3554 labels, values, G_N_ELEMENTS(labels),
3555 sp_ddc_width_value_changed, 0.01, 0, 100 );
3556 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3557 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3558 }
3560 {
3561 /* Thinning */
3562 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
3563 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
3564 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
3565 _("Stroke Thinning"), _("Thinning:"),
3566 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
3567 "tools.calligraphic", "thinning", 0.1,
3568 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3569 -1.0, 1.0, 0.01, 0.1,
3570 labels, values, G_N_ELEMENTS(labels),
3571 sp_ddc_velthin_value_changed, 0.01, 2);
3572 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3573 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3574 }
3576 {
3577 /* Angle */
3578 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
3579 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3580 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
3581 _("Pen Angle"), _("Angle:"),
3582 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
3583 "tools.calligraphic", "angle", 30,
3584 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
3585 -90.0, 90.0, 1.0, 10.0,
3586 labels, values, G_N_ELEMENTS(labels),
3587 sp_ddc_angle_value_changed, 1, 0 );
3588 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3589 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3590 g_object_set_data( holder, "angle", eact );
3591 calligraphy_angle = eact;
3592 }
3594 {
3595 /* Fixation */
3596 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
3597 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
3598 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
3599 _("Fixation"), _("Fixation:"),
3600 _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
3601 "tools.calligraphic", "flatness", 0.9,
3602 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3603 0.0, 1.0, 0.01, 0.1,
3604 labels, values, G_N_ELEMENTS(labels),
3605 sp_ddc_flatness_value_changed, 0.01, 2 );
3606 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3607 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3608 }
3610 {
3611 /* Cap Rounding */
3612 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
3613 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
3614 // TRANSLATORS: "cap" means "end" (both start and finish) here
3615 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
3616 _("Cap rounding"), _("Caps:"),
3617 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
3618 "tools.calligraphic", "cap_rounding", 0.0,
3619 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3620 0.0, 5.0, 0.01, 0.1,
3621 labels, values, G_N_ELEMENTS(labels),
3622 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
3623 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3624 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3625 }
3627 {
3628 /* Tremor */
3629 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
3630 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
3631 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
3632 _("Stroke Tremor"), _("Tremor:"),
3633 _("Increase to make strokes rugged and trembling"),
3634 "tools.calligraphic", "tremor", 0.0,
3635 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3636 0.0, 1.0, 0.01, 0.1,
3637 labels, values, G_N_ELEMENTS(labels),
3638 sp_ddc_tremor_value_changed, 0.01, 2 );
3640 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3641 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3642 }
3644 {
3645 /* Wiggle */
3646 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
3647 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
3648 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
3649 _("Pen Wiggle"), _("Wiggle:"),
3650 _("Increase to make the pen waver and wiggle"),
3651 "tools.calligraphic", "wiggle", 0.0,
3652 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3653 0.0, 1.0, 0.01, 0.1,
3654 labels, values, G_N_ELEMENTS(labels),
3655 sp_ddc_wiggle_value_changed, 0.01, 2 );
3656 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3657 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3658 }
3660 {
3661 /* Mass */
3662 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
3663 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
3664 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
3665 _("Pen Mass"), _("Mass:"),
3666 _("Increase to make the pen drag behind, as if slowed by inertia"),
3667 "tools.calligraphic", "mass", 0.02,
3668 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3669 0.0, 1.0, 0.01, 0.1,
3670 labels, values, G_N_ELEMENTS(labels),
3671 sp_ddc_mass_value_changed, 0.01, 2 );
3672 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3673 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3674 }
3677 /* Trace Background button */
3678 {
3679 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
3680 _("Trace Background"),
3681 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
3682 "trace_background",
3683 Inkscape::ICON_SIZE_DECORATION );
3684 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3685 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), holder);
3686 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
3687 g_object_set_data( holder, "tracebackground", act );
3688 }
3690 /* Use Pressure button */
3691 {
3692 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
3693 _("Pressure"),
3694 _("Use the pressure of the input device to alter the width of the pen"),
3695 "use_pressure",
3696 Inkscape::ICON_SIZE_DECORATION );
3697 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3698 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), holder);
3699 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
3700 g_object_set_data( holder, "usepressure", act );
3701 }
3703 /* Use Tilt button */
3704 {
3705 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
3706 _("Tilt"),
3707 _("Use the tilt of the input device to alter the angle of the pen's nib"),
3708 "use_tilt",
3709 Inkscape::ICON_SIZE_DECORATION );
3710 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3711 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), holder );
3712 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3713 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3714 g_object_set_data( holder, "usetilt", act );
3715 }
3717 /*calligraphic profile */
3718 {
3719 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
3720 gchar *pref_path;
3723 GtkTreeIter iter;
3724 gtk_list_store_append( model, &iter );
3725 gtk_list_store_set( model, &iter, 0, _("No preset"), 1, 0, -1 );
3727 //TODO: switch back to prefs API
3728 Inkscape::XML::Node *repr = inkscape_get_repr(INKSCAPE, "tools.calligraphic.preset" );
3729 Inkscape::XML::Node *child_repr = sp_repr_children(repr);
3730 int ii=1;
3731 while (child_repr) {
3732 GtkTreeIter iter;
3733 char *preset_name = (char *) child_repr->attribute("name");
3734 gtk_list_store_append( model, &iter );
3735 gtk_list_store_set( model, &iter, 0, preset_name, 1, ++ii, -1 );
3736 child_repr = sp_repr_next(child_repr);
3737 }
3739 pref_path = NULL;
3740 EgeSelectOneAction* act1 = ege_select_one_action_new( "SetProfileAction", "" , ("Change calligraphic profile"), NULL, GTK_TREE_MODEL(model) );
3741 ege_select_one_action_set_appearance( act1, "compact" );
3742 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(sp_ddc_change_profile), holder );
3743 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
3744 g_object_set_data( holder, "profile_selector", act1 );
3746 }
3748 /*Save or delete calligraphic profile */
3749 {
3750 GtkAction* act = gtk_action_new( "SaveDeleteProfileAction",
3751 _("Defaults"),
3752 _("Save current settings as new profile"),
3753 GTK_STOCK_SAVE );
3754 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_dcc_save_profile), holder );
3757 gtk_action_group_add_action( mainActions, act );
3758 gtk_action_set_sensitive( act, TRUE );
3759 g_object_set_data( holder, "profile_save_delete", act );
3760 }
3761 }
3762 }
3765 //########################
3766 //## Circle / Arc ##
3767 //########################
3769 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
3770 {
3771 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
3772 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
3774 if (v1 == 0 && v2 == 0) {
3775 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
3776 gtk_action_set_sensitive( ocb, FALSE );
3777 gtk_action_set_sensitive( make_whole, FALSE );
3778 }
3779 } else {
3780 gtk_action_set_sensitive( ocb, TRUE );
3781 gtk_action_set_sensitive( make_whole, TRUE );
3782 }
3783 }
3785 static void
3786 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
3787 {
3788 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3790 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3791 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
3792 }
3794 // quit if run by the attr_changed listener
3795 if (g_object_get_data( tbl, "freeze" )) {
3796 return;
3797 }
3799 // in turn, prevent listener from responding
3800 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3802 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
3804 bool modmade = false;
3805 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3806 items != NULL;
3807 items = items->next)
3808 {
3809 SPItem *item = SP_ITEM(items->data);
3811 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
3813 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
3814 SPArc *arc = SP_ARC(item);
3816 if (!strcmp(value_name, "start"))
3817 ge->start = (adj->value * M_PI)/ 180;
3818 else
3819 ge->end = (adj->value * M_PI)/ 180;
3821 sp_genericellipse_normalize(ge);
3822 ((SPObject *)arc)->updateRepr();
3823 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
3825 modmade = true;
3826 }
3827 }
3829 g_free(namespaced_name);
3831 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
3833 sp_arctb_sensitivize( tbl, adj->value, other->value );
3835 if (modmade) {
3836 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
3837 _("Arc: Change start/end"));
3838 }
3840 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3841 }
3844 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
3845 {
3846 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
3847 }
3849 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
3850 {
3851 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
3852 }
3854 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
3855 {
3856 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3857 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3858 if ( ege_select_one_action_get_active( act ) != 0 ) {
3859 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
3860 } else {
3861 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
3862 }
3863 }
3865 // quit if run by the attr_changed listener
3866 if (g_object_get_data( tbl, "freeze" )) {
3867 return;
3868 }
3870 // in turn, prevent listener from responding
3871 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3873 bool modmade = false;
3875 if ( ege_select_one_action_get_active(act) != 0 ) {
3876 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3877 items != NULL;
3878 items = items->next)
3879 {
3880 if (SP_IS_ARC((SPItem *) items->data)) {
3881 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3882 repr->setAttribute("sodipodi:open", "true");
3883 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3884 modmade = true;
3885 }
3886 }
3887 } else {
3888 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3889 items != NULL;
3890 items = items->next)
3891 {
3892 if (SP_IS_ARC((SPItem *) items->data)) {
3893 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3894 repr->setAttribute("sodipodi:open", NULL);
3895 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3896 modmade = true;
3897 }
3898 }
3899 }
3901 if (modmade) {
3902 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
3903 _("Arc: Change open/closed"));
3904 }
3906 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3907 }
3909 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
3910 {
3911 GtkAdjustment *adj;
3912 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
3913 gtk_adjustment_set_value(adj, 0.0);
3914 gtk_adjustment_value_changed(adj);
3916 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
3917 gtk_adjustment_set_value(adj, 0.0);
3918 gtk_adjustment_value_changed(adj);
3920 spinbutton_defocus( GTK_OBJECT(obj) );
3921 }
3923 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3924 gchar const */*old_value*/, gchar const */*new_value*/,
3925 bool /*is_interactive*/, gpointer data)
3926 {
3927 GObject *tbl = G_OBJECT(data);
3929 // quit if run by the _changed callbacks
3930 if (g_object_get_data( tbl, "freeze" )) {
3931 return;
3932 }
3934 // in turn, prevent callbacks from responding
3935 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3937 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
3938 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
3940 GtkAdjustment *adj1,*adj2;
3941 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
3942 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
3943 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
3944 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
3946 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
3948 char const *openstr = NULL;
3949 openstr = repr->attribute("sodipodi:open");
3950 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
3952 if (openstr) {
3953 ege_select_one_action_set_active( ocb, 1 );
3954 } else {
3955 ege_select_one_action_set_active( ocb, 0 );
3956 }
3958 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3959 }
3961 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
3962 NULL, /* child_added */
3963 NULL, /* child_removed */
3964 arc_tb_event_attr_changed,
3965 NULL, /* content_changed */
3966 NULL /* order_changed */
3967 };
3970 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3971 {
3972 int n_selected = 0;
3973 Inkscape::XML::Node *repr = NULL;
3975 purge_repr_listener( tbl, tbl );
3977 for (GSList const *items = selection->itemList();
3978 items != NULL;
3979 items = items->next)
3980 {
3981 if (SP_IS_ARC((SPItem *) items->data)) {
3982 n_selected++;
3983 repr = SP_OBJECT_REPR((SPItem *) items->data);
3984 }
3985 }
3987 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3989 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3990 if (n_selected == 0) {
3991 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3992 } else if (n_selected == 1) {
3993 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3994 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3996 if (repr) {
3997 g_object_set_data( tbl, "repr", repr );
3998 Inkscape::GC::anchor(repr);
3999 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
4000 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
4001 }
4002 } else {
4003 // FIXME: implement averaging of all parameters for multiple selected
4004 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
4005 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
4006 sp_arctb_sensitivize( tbl, 1, 0 );
4007 }
4008 }
4011 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4012 {
4013 EgeAdjustmentAction* eact = 0;
4016 {
4017 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
4018 ege_output_action_set_use_markup( act, TRUE );
4019 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4020 g_object_set_data( holder, "mode_action", act );
4021 }
4023 /* Start */
4024 {
4025 eact = create_adjustment_action( "ArcStartAction",
4026 _("Start"), _("Start:"),
4027 _("The angle (in degrees) from the horizontal to the arc's start point"),
4028 "tools.shapes.arc", "start", 0.0,
4029 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
4030 -360.0, 360.0, 1.0, 10.0,
4031 0, 0, 0,
4032 sp_arctb_start_value_changed);
4033 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4034 }
4036 /* End */
4037 {
4038 eact = create_adjustment_action( "ArcEndAction",
4039 _("End"), _("End:"),
4040 _("The angle (in degrees) from the horizontal to the arc's end point"),
4041 "tools.shapes.arc", "end", 0.0,
4042 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
4043 -360.0, 360.0, 1.0, 10.0,
4044 0, 0, 0,
4045 sp_arctb_end_value_changed);
4046 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4047 }
4049 /* Segments / Pie checkbox */
4050 {
4051 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
4053 GtkTreeIter iter;
4054 gtk_list_store_append( model, &iter );
4055 gtk_list_store_set( model, &iter,
4056 0, _("Closed arc"),
4057 1, _("Switch to segment (closed shape with two radii)"),
4058 2, "circle_closed_arc",
4059 -1 );
4061 gtk_list_store_append( model, &iter );
4062 gtk_list_store_set( model, &iter,
4063 0, _("Open Arc"),
4064 1, _("Switch to arc (unclosed shape)"),
4065 2, "circle_open_arc",
4066 -1 );
4068 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
4069 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
4070 g_object_set_data( holder, "open_action", act );
4072 ege_select_one_action_set_appearance( act, "full" );
4073 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
4074 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
4075 ege_select_one_action_set_icon_column( act, 2 );
4076 ege_select_one_action_set_tooltip_column( act, 1 );
4078 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
4079 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
4080 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
4081 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
4082 }
4084 /* Make Whole */
4085 {
4086 InkAction* inky = ink_action_new( "ArcResetAction",
4087 _("Make whole"),
4088 _("Make the shape a whole ellipse, not arc or segment"),
4089 "reset_circle",
4090 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4091 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
4092 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4093 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
4094 g_object_set_data( holder, "make_whole", inky );
4095 }
4097 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
4098 // sensitivize make whole and open checkbox
4099 {
4100 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
4101 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
4102 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
4103 }
4106 sigc::connection *connection = new sigc::connection(
4107 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
4108 );
4109 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
4110 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
4111 }
4116 // toggle button callbacks and updaters
4118 //########################
4119 //## Dropper ##
4120 //########################
4122 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
4123 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
4124 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
4125 if ( set_action ) {
4126 if ( gtk_toggle_action_get_active( act ) ) {
4127 gtk_action_set_sensitive( set_action, TRUE );
4128 } else {
4129 gtk_action_set_sensitive( set_action, FALSE );
4130 }
4131 }
4133 spinbutton_defocus(GTK_OBJECT(tbl));
4134 }
4136 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
4137 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
4138 spinbutton_defocus(GTK_OBJECT(tbl));
4139 }
4142 /**
4143 * Dropper auxiliary toolbar construction and setup.
4144 *
4145 * TODO: Would like to add swatch of current color.
4146 * TODO: Add queue of last 5 or so colors selected with new swatches so that
4147 * can drag and drop places. Will provide a nice mixing palette.
4148 */
4149 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
4150 {
4151 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
4153 {
4154 EgeOutputAction* act = ege_output_action_new( "DropperOpacityAction", _("Opacity:"), "", 0 );
4155 ege_output_action_set_use_markup( act, TRUE );
4156 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4157 }
4159 {
4160 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
4161 _("Pick opacity"),
4162 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
4163 NULL,
4164 Inkscape::ICON_SIZE_DECORATION );
4165 g_object_set( act, "short_label", _("Pick"), NULL );
4166 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4167 g_object_set_data( holder, "pick_action", act );
4168 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
4169 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
4170 }
4172 {
4173 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
4174 _("Assign opacity"),
4175 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
4176 NULL,
4177 Inkscape::ICON_SIZE_DECORATION );
4178 g_object_set( act, "short_label", _("Assign"), NULL );
4179 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4180 g_object_set_data( holder, "set_action", act );
4181 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
4182 // make sure it's disabled if we're not picking alpha
4183 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
4184 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
4185 }
4186 }
4189 //########################
4190 //## Text Toolbox ##
4191 //########################
4192 /*
4193 static void
4194 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
4195 {
4196 //Call back for letter sizing spinbutton
4197 }
4199 static void
4200 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
4201 {
4202 //Call back for line height spinbutton
4203 }
4205 static void
4206 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
4207 {
4208 //Call back for horizontal kerning spinbutton
4209 }
4211 static void
4212 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
4213 {
4214 //Call back for vertical kerning spinbutton
4215 }
4217 static void
4218 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
4219 {
4220 //Call back for letter rotation spinbutton
4221 }*/
4223 namespace {
4225 bool popdown_visible = false;
4226 bool popdown_hasfocus = false;
4228 void
4229 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
4230 {
4231 SPStyle *query =
4232 sp_style_new (SP_ACTIVE_DOCUMENT);
4234 int result_fontspec =
4235 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4237 int result_family =
4238 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
4240 int result_style =
4241 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
4243 int result_numbers =
4244 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4246 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4248 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4249 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
4250 {
4251 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
4253 if (repr)
4254 {
4255 sp_style_read_from_repr (query, repr);
4256 }
4257 else
4258 {
4259 return;
4260 }
4261 }
4263 if (query->text)
4264 {
4265 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
4266 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
4267 gtk_entry_set_text (GTK_ENTRY (entry), "");
4269 } else if (query->text->font_specification.value || query->text->font_family.value) {
4271 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
4273 // Get the font that corresponds
4274 Glib::ustring familyName;
4276 font_instance * font = font_factory::Default()->FaceFromStyle(query);
4277 if (font) {
4278 familyName = font_factory::Default()->GetUIFamilyString(font->descr);
4279 font->Unref();
4280 font = NULL;
4281 }
4283 gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
4285 Gtk::TreePath path;
4286 try {
4287 path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
4288 } catch (...) {
4289 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
4290 return;
4291 }
4293 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4294 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4296 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
4298 gtk_tree_selection_select_path (tselection, path.gobj());
4299 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4301 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
4302 }
4304 //Size
4305 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4306 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
4307 g_object_set_data (tbl, "size-block", gpointer(1));
4308 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
4309 g_object_set_data (tbl, "size-block", gpointer(0));
4310 free (str);
4312 //Anchor
4313 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
4314 {
4315 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
4316 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4317 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4318 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4319 }
4320 else
4321 {
4322 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
4323 {
4324 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
4325 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4326 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4327 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4328 }
4329 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
4330 {
4331 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
4332 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4333 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4334 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4335 }
4336 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
4337 {
4338 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
4339 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4340 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4341 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4342 }
4343 }
4345 //Style
4346 {
4347 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
4349 gboolean active = gtk_toggle_button_get_active (button);
4350 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
4352 if (active != check)
4353 {
4354 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4355 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4356 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4357 }
4358 }
4360 {
4361 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
4363 gboolean active = gtk_toggle_button_get_active (button);
4364 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
4366 if (active != check)
4367 {
4368 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4369 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4370 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4371 }
4372 }
4374 //Orientation
4375 //locking both buttons, changing one affect all group (both)
4376 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
4377 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4379 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
4380 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
4382 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
4383 {
4384 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4385 }
4386 else
4387 {
4388 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
4389 }
4390 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4391 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
4392 }
4394 sp_style_unref(query);
4395 }
4397 void
4398 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
4399 {
4400 sp_text_toolbox_selection_changed (selection, tbl);
4401 }
4403 void
4404 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4405 {
4406 sp_text_toolbox_selection_changed (NULL, tbl);
4407 }
4409 void
4410 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4411 GObject *tbl)
4412 {
4413 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4414 GtkTreeModel *model = 0;
4415 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4416 GtkTreeIter iter;
4417 char *family = 0;
4419 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4420 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4422 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
4423 return;
4424 }
4426 gtk_tree_model_get (model, &iter, 0, &family, -1);
4428 if (g_object_get_data (G_OBJECT (selection), "block"))
4429 {
4430 gtk_entry_set_text (GTK_ENTRY (entry), family);
4431 return;
4432 }
4434 gtk_entry_set_text (GTK_ENTRY (entry), family);
4436 SPStyle *query =
4437 sp_style_new (SP_ACTIVE_DOCUMENT);
4439 int result_fontspec =
4440 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4442 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
4444 SPCSSAttr *css = sp_repr_css_attr_new ();
4447 // First try to get the font spec from the stored value
4448 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
4450 if (fontSpec.empty()) {
4451 // Construct a new font specification if it does not yet exist
4452 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
4453 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
4454 fontFromStyle->Unref();
4455 }
4457 if (!fontSpec.empty()) {
4458 Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
4459 if (!newFontSpec.empty() && fontSpec != newFontSpec) {
4460 font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
4461 if (font) {
4462 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
4464 // Set all the these just in case they were altered when finding the best
4465 // match for the new family and old style...
4467 gchar c[256];
4469 font->Family(c, 256);
4470 sp_repr_css_set_property (css, "font-family", c);
4472 font->Attribute( "weight", c, 256);
4473 sp_repr_css_set_property (css, "font-weight", c);
4475 font->Attribute("style", c, 256);
4476 sp_repr_css_set_property (css, "font-style", c);
4478 font->Attribute("stretch", c, 256);
4479 sp_repr_css_set_property (css, "font-stretch", c);
4481 font->Attribute("variant", c, 256);
4482 sp_repr_css_set_property (css, "font-variant", c);
4484 font->Unref();
4485 }
4486 }
4487 }
4489 // If querying returned nothing, set the default style of the tool (for new texts)
4490 if (result_fontspec == QUERY_STYLE_NOTHING)
4491 {
4492 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4493 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
4494 }
4495 else
4496 {
4497 sp_desktop_set_style (desktop, css, true, true);
4498 }
4500 sp_style_unref(query);
4502 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4503 _("Text: Change font family"));
4504 sp_repr_css_attr_unref (css);
4505 free (family);
4506 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4508 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4509 }
4511 void
4512 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
4513 GObject *tbl)
4514 {
4515 const char *family = gtk_entry_get_text (entry);
4517 try {
4518 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
4519 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4520 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4521 gtk_tree_selection_select_path (selection, path.gobj());
4522 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4523 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4524 } catch (...) {
4525 if (family && strlen (family))
4526 {
4527 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4528 }
4529 }
4530 }
4532 void
4533 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
4534 gpointer data)
4535 {
4536 if (g_object_get_data (G_OBJECT (button), "block")) return;
4537 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
4538 int prop = GPOINTER_TO_INT(data);
4540 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4541 SPCSSAttr *css = sp_repr_css_attr_new ();
4543 switch (prop)
4544 {
4545 case 0:
4546 {
4547 sp_repr_css_set_property (css, "text-anchor", "start");
4548 sp_repr_css_set_property (css, "text-align", "start");
4549 break;
4550 }
4551 case 1:
4552 {
4553 sp_repr_css_set_property (css, "text-anchor", "middle");
4554 sp_repr_css_set_property (css, "text-align", "center");
4555 break;
4556 }
4558 case 2:
4559 {
4560 sp_repr_css_set_property (css, "text-anchor", "end");
4561 sp_repr_css_set_property (css, "text-align", "end");
4562 break;
4563 }
4565 case 3:
4566 {
4567 sp_repr_css_set_property (css, "text-anchor", "start");
4568 sp_repr_css_set_property (css, "text-align", "justify");
4569 break;
4570 }
4571 }
4573 SPStyle *query =
4574 sp_style_new (SP_ACTIVE_DOCUMENT);
4575 int result_numbers =
4576 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4578 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4579 if (result_numbers == QUERY_STYLE_NOTHING)
4580 {
4581 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4582 }
4584 sp_style_unref(query);
4586 sp_desktop_set_style (desktop, css, true, true);
4587 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4588 _("Text: Change alignment"));
4589 sp_repr_css_attr_unref (css);
4591 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4592 }
4594 void
4595 sp_text_toolbox_style_toggled (GtkToggleButton *button,
4596 gpointer data)
4597 {
4598 if (g_object_get_data (G_OBJECT (button), "block")) return;
4600 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4601 SPCSSAttr *css = sp_repr_css_attr_new ();
4602 int prop = GPOINTER_TO_INT(data);
4603 bool active = gtk_toggle_button_get_active (button);
4605 SPStyle *query =
4606 sp_style_new (SP_ACTIVE_DOCUMENT);
4608 int result_fontspec =
4609 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4611 int result_family =
4612 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
4614 int result_style =
4615 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
4617 int result_numbers =
4618 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4620 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
4621 Glib::ustring newFontSpec = "";
4623 if (fontSpec.empty()) {
4624 // Construct a new font specification if it does not yet exist
4625 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
4626 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
4627 fontFromStyle->Unref();
4628 }
4630 switch (prop)
4631 {
4632 case 0:
4633 {
4634 if (!fontSpec.empty()) {
4635 newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
4636 }
4637 if (fontSpec != newFontSpec) {
4638 // Don't even set the bold if the font didn't exist on the system
4639 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
4640 }
4641 break;
4642 }
4644 case 1:
4645 {
4646 if (!fontSpec.empty()) {
4647 newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
4648 }
4649 if (fontSpec != newFontSpec) {
4650 // Don't even set the italic if the font didn't exist on the system
4651 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
4652 }
4653 break;
4654 }
4655 }
4657 if (!newFontSpec.empty()) {
4658 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
4659 }
4661 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4662 if (result_fontspec == QUERY_STYLE_NOTHING)
4663 {
4664 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4665 }
4667 sp_style_unref(query);
4669 sp_desktop_set_style (desktop, css, true, true);
4670 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4671 _("Text: Change font style"));
4672 sp_repr_css_attr_unref (css);
4674 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4675 }
4677 void
4678 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
4679 gpointer data)
4680 {
4681 if (g_object_get_data (G_OBJECT (button), "block")) {
4682 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4683 return;
4684 }
4686 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4687 SPCSSAttr *css = sp_repr_css_attr_new ();
4688 int prop = GPOINTER_TO_INT(data);
4690 switch (prop)
4691 {
4692 case 0:
4693 {
4694 sp_repr_css_set_property (css, "writing-mode", "lr");
4695 break;
4696 }
4698 case 1:
4699 {
4700 sp_repr_css_set_property (css, "writing-mode", "tb");
4701 break;
4702 }
4703 }
4705 SPStyle *query =
4706 sp_style_new (SP_ACTIVE_DOCUMENT);
4707 int result_numbers =
4708 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4710 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4711 if (result_numbers == QUERY_STYLE_NOTHING)
4712 {
4713 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4714 }
4716 sp_desktop_set_style (desktop, css, true, true);
4717 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4718 _("Text: Change orientation"));
4719 sp_repr_css_attr_unref (css);
4721 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4722 }
4724 gboolean
4725 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4726 {
4727 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4728 if (!desktop) return FALSE;
4730 switch (get_group0_keyval (event)) {
4731 case GDK_Escape: // defocus
4732 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4733 sp_text_toolbox_selection_changed (NULL, tbl); // update
4734 return TRUE; // I consumed the event
4735 break;
4736 }
4737 return FALSE;
4738 }
4740 gboolean
4741 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
4742 {
4743 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4744 if (!desktop) return FALSE;
4746 switch (get_group0_keyval (event)) {
4747 case GDK_KP_Enter:
4748 case GDK_Return:
4749 case GDK_Escape: // defocus
4750 gtk_widget_hide (w);
4751 popdown_visible = false;
4752 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4753 return TRUE; // I consumed the event
4754 break;
4755 case GDK_w:
4756 case GDK_W:
4757 if (event->state & GDK_CONTROL_MASK) {
4758 gtk_widget_hide (w);
4759 popdown_visible = false;
4760 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4761 return TRUE; // I consumed the event
4762 }
4763 break;
4764 }
4765 return FALSE;
4766 }
4769 void
4770 sp_text_toolbox_size_changed (GtkComboBox *cbox,
4771 GObject *tbl)
4772 {
4773 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4775 if (g_object_get_data (tbl, "size-block")) return;
4777 // If this is not from selecting a size in the list (in which case get_active will give the
4778 // index of the selected item, otherwise -1) and not from user pressing Enter/Return, do not
4779 // process this event. This fixes GTK's stupid insistence on sending an activate change every
4780 // time any character gets typed or deleted, which made this control nearly unusable in 0.45.
4781 if (gtk_combo_box_get_active (cbox) < 0 && !g_object_get_data (tbl, "enter-pressed"))
4782 return;
4784 gchar *endptr;
4785 gdouble value = -1;
4786 char *text = gtk_combo_box_get_active_text (cbox);
4787 if (text) {
4788 value = g_strtod (text, &endptr);
4789 if (endptr == text) // conversion failed, non-numeric input
4790 value = -1;
4791 free (text);
4792 }
4793 if (value <= 0) {
4794 return; // could not parse value
4795 }
4797 SPCSSAttr *css = sp_repr_css_attr_new ();
4798 Inkscape::CSSOStringStream osfs;
4799 osfs << value;
4800 sp_repr_css_set_property (css, "font-size", osfs.str().c_str());
4802 SPStyle *query =
4803 sp_style_new (SP_ACTIVE_DOCUMENT);
4804 int result_numbers =
4805 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4807 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4808 if (result_numbers == QUERY_STYLE_NOTHING)
4809 {
4810 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4811 }
4813 sp_style_unref(query);
4815 sp_desktop_set_style (desktop, css, true, true);
4816 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
4817 _("Text: Change font size"));
4818 sp_repr_css_attr_unref (css);
4820 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4821 }
4823 gboolean
4824 sp_text_toolbox_size_focusout (GtkWidget */*w*/, GdkEventFocus */*event*/, GObject *tbl)
4825 {
4826 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4827 if (!desktop) return FALSE;
4829 if (!g_object_get_data (tbl, "esc-pressed")) {
4830 g_object_set_data (tbl, "enter-pressed", gpointer(1));
4831 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4832 sp_text_toolbox_size_changed (cbox, tbl);
4833 g_object_set_data (tbl, "enter-pressed", gpointer(0));
4834 }
4835 return FALSE; // I consumed the event
4836 }
4839 gboolean
4840 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4841 {
4842 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4843 if (!desktop) return FALSE;
4845 switch (get_group0_keyval (event)) {
4846 case GDK_Escape: // defocus
4847 g_object_set_data (tbl, "esc-pressed", gpointer(1));
4848 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4849 g_object_set_data (tbl, "esc-pressed", gpointer(0));
4850 return TRUE; // I consumed the event
4851 break;
4852 case GDK_Return: // defocus
4853 case GDK_KP_Enter:
4854 g_object_set_data (tbl, "enter-pressed", gpointer(1));
4855 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4856 sp_text_toolbox_size_changed (cbox, tbl);
4857 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4858 g_object_set_data (tbl, "enter-pressed", gpointer(0));
4859 return TRUE; // I consumed the event
4860 break;
4861 }
4862 return FALSE;
4863 }
4865 void
4866 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
4867 GObject *tbl)
4868 {
4869 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4870 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4871 int x, y;
4873 if (!popdown_visible)
4874 {
4875 gdk_window_get_origin (widget->window, &x, &y);
4876 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
4877 gtk_widget_show_all (popdown);
4878 //sp_transientize (popdown);
4880 gdk_pointer_grab (widget->window, TRUE,
4881 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
4882 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
4883 GDK_POINTER_MOTION_MASK),
4884 NULL, NULL, GDK_CURRENT_TIME);
4886 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
4888 popdown_visible = true;
4889 }
4890 else
4891 {
4892 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4893 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4894 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4895 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4896 gtk_widget_hide (popdown);
4897 popdown_visible = false;
4898 }
4899 }
4901 gboolean
4902 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
4903 GdkEventFocus */*event*/,
4904 GObject */*tbl*/)
4905 {
4906 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
4907 return FALSE;
4908 }
4910 gboolean
4911 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
4912 GdkEventFocus */*event*/,
4913 GObject */*tbl*/)
4914 {
4915 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4917 if (popdown_hasfocus) {
4918 gtk_widget_hide (popdown);
4919 popdown_hasfocus = false;
4920 popdown_visible = false;
4921 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4922 return TRUE;
4923 }
4924 return FALSE;
4925 }
4927 gboolean
4928 sp_text_toolbox_popdown_focus_in (GtkWidget */*popdown*/,
4929 GdkEventFocus */*event*/,
4930 GObject */*tbl*/)
4931 {
4932 popdown_hasfocus = true;
4933 return TRUE;
4934 }
4937 void
4938 cell_data_func (GtkTreeViewColumn */*column*/,
4939 GtkCellRenderer *cell,
4940 GtkTreeModel *tree_model,
4941 GtkTreeIter *iter,
4942 gpointer /*data*/)
4943 {
4944 char *family,
4945 *family_escaped,
4946 *sample_escaped;
4948 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
4950 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
4952 family_escaped = g_markup_escape_text (family, -1);
4953 sample_escaped = g_markup_escape_text (sample, -1);
4955 std::stringstream markup;
4956 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
4957 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
4959 free (family);
4960 free (family_escaped);
4961 free (sample_escaped);
4962 }
4964 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
4965 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
4966 if (completion) {
4967 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
4968 g_object_unref (completion);
4969 }
4970 }
4972 GtkWidget*
4973 sp_text_toolbox_new (SPDesktop *desktop)
4974 {
4975 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
4977 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4978 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4980 GtkTooltips *tt = gtk_tooltips_new();
4981 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4983 ////////////Family
4984 //Window
4985 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4986 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4988 //Entry
4989 GtkWidget *entry = gtk_entry_new ();
4990 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4991 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4992 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4993 gtk_entry_completion_set_text_column (completion, 0);
4994 gtk_entry_completion_set_minimum_key_length (completion, 1);
4995 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4996 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4997 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4998 aux_toolbox_space (tbl, 1);
4999 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
5000 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
5002 //Button
5003 GtkWidget *button = gtk_button_new ();
5004 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
5005 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
5007 //Popdown
5008 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
5009 GtkWidget *treeview = gtk_tree_view_new ();
5011 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
5012 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
5013 gtk_tree_view_column_pack_start (column, cell, FALSE);
5014 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
5015 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
5016 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
5018 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
5019 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
5020 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
5022 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
5024 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
5025 gtk_container_add (GTK_CONTAINER (sw), treeview);
5027 gtk_container_add (GTK_CONTAINER (window), sw);
5028 gtk_widget_set_size_request (window, 300, 450);
5030 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
5031 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
5032 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
5034 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
5036 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
5037 g_signal_connect (G_OBJECT (window), "focus-in-event", G_CALLBACK (sp_text_toolbox_popdown_focus_in), tbl);
5038 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
5040 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
5041 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
5043 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
5044 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
5045 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
5046 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
5047 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
5049 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
5050 aux_toolbox_space (tbl, 1);
5051 GtkWidget *box = gtk_event_box_new ();
5052 gtk_container_add (GTK_CONTAINER (box), image);
5053 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
5054 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
5055 GtkTooltips *tooltips = gtk_tooltips_new ();
5056 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
5057 gtk_widget_hide (GTK_WIDGET (box));
5058 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
5060 ////////////Size
5061 const char *sizes[] = {
5062 "4", "6", "8", "9", "10", "11", "12", "13", "14",
5063 "16", "18", "20", "22", "24", "28",
5064 "32", "36", "40", "48", "56", "64", "72", "144"
5065 };
5067 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
5068 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
5069 gtk_widget_set_size_request (cbox, 80, -1);
5070 aux_toolbox_space (tbl, 1);
5071 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
5072 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
5073 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
5074 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), tbl);
5075 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "focus-out-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_focusout), tbl);
5077 //spacer
5078 aux_toolbox_space (tbl, 4);
5079 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
5081 ////////////Text anchor
5082 GtkWidget *group = gtk_radio_button_new (NULL);
5083 GtkWidget *row = gtk_hbox_new (FALSE, 4);
5084 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
5086 // left
5087 GtkWidget *rbutton = group;
5088 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5089 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
5090 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5092 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5093 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
5094 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
5095 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
5097 // center
5098 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5099 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5100 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
5101 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5103 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5104 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
5105 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
5106 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
5108 // right
5109 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5110 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5111 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
5112 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5114 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5115 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
5116 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
5117 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
5119 // fill
5120 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5121 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5122 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
5123 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5125 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5126 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
5127 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
5128 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
5130 aux_toolbox_space (tbl, 1);
5131 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
5133 //spacer
5134 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
5136 ////////////Text style
5137 row = gtk_hbox_new (FALSE, 4);
5139 // bold
5140 rbutton = gtk_toggle_button_new ();
5141 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5142 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
5143 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5144 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
5146 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5147 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
5148 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
5150 // italic
5151 rbutton = gtk_toggle_button_new ();
5152 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5153 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
5154 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5155 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
5157 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5158 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
5159 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
5161 aux_toolbox_space (tbl, 1);
5162 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
5164 //spacer
5165 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
5167 ////////////Text orientation
5168 group = gtk_radio_button_new (NULL);
5169 row = gtk_hbox_new (FALSE, 4);
5170 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
5172 // horizontal
5173 rbutton = group;
5174 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5175 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
5176 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5177 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
5179 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5180 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
5181 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
5183 // vertical
5184 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
5185 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
5186 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
5187 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
5188 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
5190 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
5191 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
5192 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
5193 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
5196 //watch selection
5197 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
5199 sigc::connection *c_selection_changed =
5200 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
5201 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
5202 pool->add_connection ("selection-changed", c_selection_changed);
5204 sigc::connection *c_selection_modified =
5205 new sigc::connection (sp_desktop_selection (desktop)->connectModified
5206 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
5207 pool->add_connection ("selection-modified", c_selection_modified);
5209 sigc::connection *c_subselection_changed =
5210 new sigc::connection (desktop->connectToolSubselectionChanged
5211 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
5212 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
5214 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
5217 gtk_widget_show_all (tbl);
5218 return tbl;
5220 } // end of sp_text_toolbox_new()
5222 }//<unnamed> namespace
5225 //#########################
5226 //## Connector ##
5227 //#########################
5229 static void sp_connector_path_set_avoid(void)
5230 {
5231 cc_selection_set_avoid(true);
5232 }
5235 static void sp_connector_path_set_ignore(void)
5236 {
5237 cc_selection_set_avoid(false);
5238 }
5242 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
5243 {
5244 // quit if run by the _changed callbacks
5245 if (g_object_get_data( tbl, "freeze" )) {
5246 return;
5247 }
5249 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
5250 SPDocument *doc = sp_desktop_document(desktop);
5252 if (!sp_document_get_undo_sensitive(doc))
5253 {
5254 return;
5255 }
5257 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5259 if ( repr->attribute("inkscape:connector-spacing") ) {
5260 gdouble priorValue = gtk_adjustment_get_value(adj);
5261 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
5262 if ( priorValue == gtk_adjustment_get_value(adj) ) {
5263 return;
5264 }
5265 } else if ( adj->value == defaultConnSpacing ) {
5266 return;
5267 }
5269 // in turn, prevent callbacks from responding
5270 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
5272 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
5273 SP_OBJECT(desktop->namedview)->updateRepr();
5275 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
5276 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
5277 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
5278 NR::Matrix m = NR::identity();
5279 avoid_item_move(&m, item);
5280 }
5282 if (items) {
5283 g_slist_free(items);
5284 }
5286 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
5287 _("Change connector spacing"));
5289 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
5291 spinbutton_defocus(GTK_OBJECT(tbl));
5292 }
5294 static void sp_connector_graph_layout(void)
5295 {
5296 if (!SP_ACTIVE_DESKTOP) return;
5298 // hack for clones, see comment in align-and-distribute.cpp
5299 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
5300 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
5302 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
5304 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
5306 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
5307 }
5309 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
5310 {
5311 if ( gtk_toggle_action_get_active( act ) ) {
5312 prefs_set_string_attribute("tools.connector", "directedlayout",
5313 "true");
5314 } else {
5315 prefs_set_string_attribute("tools.connector", "directedlayout",
5316 "false");
5317 }
5318 }
5320 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
5321 {
5322 if ( gtk_toggle_action_get_active( act ) ) {
5323 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
5324 "true");
5325 } else {
5326 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
5327 "false");
5328 }
5329 }
5332 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
5333 {
5334 prefs_set_double_attribute("tools.connector", "length", adj->value);
5335 spinbutton_defocus(GTK_OBJECT(tbl));
5336 }
5338 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
5339 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
5340 bool /*is_interactive*/, gpointer data)
5341 {
5342 GtkWidget *tbl = GTK_WIDGET(data);
5344 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
5345 return;
5346 }
5347 if (strcmp(name, "inkscape:connector-spacing") != 0) {
5348 return;
5349 }
5351 GtkAdjustment *adj = (GtkAdjustment*)
5352 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
5353 gdouble spacing = defaultConnSpacing;
5354 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
5356 gtk_adjustment_set_value(adj, spacing);
5357 }
5360 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
5361 NULL, /* child_added */
5362 NULL, /* child_removed */
5363 connector_tb_event_attr_changed,
5364 NULL, /* content_changed */
5365 NULL /* order_changed */
5366 };
5369 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
5370 {
5371 {
5372 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
5373 _("Avoid"),
5374 _("Make connectors avoid selected objects"),
5375 "connector_avoid",
5376 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5377 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
5378 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5379 }
5381 {
5382 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
5383 _("Ignore"),
5384 _("Make connectors ignore selected objects"),
5385 "connector_ignore",
5386 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5387 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
5388 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5389 }
5391 EgeAdjustmentAction* eact = 0;
5393 // Spacing spinbox
5394 eact = create_adjustment_action( "ConnectorSpacingAction",
5395 _("Connector Spacing"), _("Spacing:"),
5396 _("The amount of space left around objects by auto-routing connectors"),
5397 "tools.connector", "spacing", defaultConnSpacing,
5398 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
5399 0, 100, 1.0, 10.0,
5400 0, 0, 0,
5401 connector_spacing_changed, 1, 0 );
5402 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5404 // Graph (connector network) layout
5405 {
5406 InkAction* inky = ink_action_new( "ConnectorGraphAction",
5407 _("Graph"),
5408 _("Nicely arrange selected connector network"),
5409 "graph_layout",
5410 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5411 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
5412 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5413 }
5415 // Default connector length spinbox
5416 eact = create_adjustment_action( "ConnectorLengthAction",
5417 _("Connector Length"), _("Length:"),
5418 _("Ideal length for connectors when layout is applied"),
5419 "tools.connector", "length", 100,
5420 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
5421 10, 1000, 10.0, 100.0,
5422 0, 0, 0,
5423 connector_length_changed, 1, 0 );
5424 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5427 // Directed edges toggle button
5428 {
5429 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
5430 _("Downwards"),
5431 _("Make connectors with end-markers (arrows) point downwards"),
5432 "directed_graph",
5433 Inkscape::ICON_SIZE_DECORATION );
5434 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5436 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
5437 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5438 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5440 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
5441 }
5443 // Avoid overlaps toggle button
5444 {
5445 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
5446 _("Remove overlaps"),
5447 _("Do not allow overlapping shapes"),
5448 "remove_overlaps",
5449 Inkscape::ICON_SIZE_DECORATION );
5450 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5452 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
5453 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5454 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5456 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
5457 }
5459 // Code to watch for changes to the connector-spacing attribute in
5460 // the XML.
5461 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5462 g_assert(repr != NULL);
5464 purge_repr_listener( holder, holder );
5466 if (repr) {
5467 g_object_set_data( holder, "repr", repr );
5468 Inkscape::GC::anchor(repr);
5469 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
5470 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
5471 }
5472 } // end of sp_connector_toolbox_prep()
5475 //#########################
5476 //## Paintbucket ##
5477 //#########################
5479 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
5480 {
5481 gint channels = ege_select_one_action_get_active( act );
5482 flood_channels_set_channels( channels );
5483 }
5485 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
5486 {
5487 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
5488 }
5490 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
5491 {
5492 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
5493 }
5495 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
5496 {
5497 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
5498 SPUnit const *unit = tracker->getActiveUnit();
5500 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
5502 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
5503 }
5505 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
5506 {
5507 // FIXME: make defaults settable via Inkscape Options
5508 struct KeyValue {
5509 char const *key;
5510 double value;
5511 } const key_values[] = {
5512 {"threshold", 15},
5513 {"offset", 0.0}
5514 };
5516 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
5517 KeyValue const &kv = key_values[i];
5518 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
5519 if ( adj ) {
5520 gtk_adjustment_set_value(adj, kv.value);
5521 }
5522 }
5524 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
5525 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
5526 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
5527 ege_select_one_action_set_active( autogap_action, 0 );
5528 }
5530 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5531 {
5532 EgeAdjustmentAction* eact = 0;
5534 {
5535 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5537 GList* items = 0;
5538 gint count = 0;
5539 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
5540 {
5541 GtkTreeIter iter;
5542 gtk_list_store_append( model, &iter );
5543 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5544 count++;
5545 }
5546 g_list_free( items );
5547 items = 0;
5548 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
5549 g_object_set( act1, "short_label", _("Fill by:"), NULL );
5550 ege_select_one_action_set_appearance( act1, "compact" );
5551 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
5552 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
5553 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
5554 g_object_set_data( holder, "channels_action", act1 );
5555 }
5557 // Spacing spinbox
5558 {
5559 eact = create_adjustment_action(
5560 "ThresholdAction",
5561 _("Fill Threshold"), _("Threshold:"),
5562 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
5563 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
5564 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
5565 0, 0, 0,
5566 paintbucket_threshold_changed, 1, 0 );
5568 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5569 }
5571 // Create the units menu.
5572 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
5573 const gchar *stored_unit = prefs_get_string_attribute("tools.paintbucket", "offsetunits");
5574 if (stored_unit)
5575 tracker->setActiveUnit(sp_unit_get_by_abbreviation(stored_unit));
5576 g_object_set_data( holder, "tracker", tracker );
5577 {
5578 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
5579 gtk_action_group_add_action( mainActions, act );
5580 }
5582 // Offset spinbox
5583 {
5584 eact = create_adjustment_action(
5585 "OffsetAction",
5586 _("Grow/shrink by"), _("Grow/shrink by:"),
5587 _("The amount to grow (positive) or shrink (negative) the created fill path"),
5588 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
5589 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
5590 0, 0, 0,
5591 paintbucket_offset_changed, 1, 2);
5592 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
5594 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5595 }
5597 /* Auto Gap */
5598 {
5599 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5601 GList* items = 0;
5602 gint count = 0;
5603 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
5604 {
5605 GtkTreeIter iter;
5606 gtk_list_store_append( model, &iter );
5607 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5608 count++;
5609 }
5610 g_list_free( items );
5611 items = 0;
5612 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
5613 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
5614 ege_select_one_action_set_appearance( act2, "compact" );
5615 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
5616 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
5617 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
5618 g_object_set_data( holder, "autogap_action", act2 );
5619 }
5621 /* Reset */
5622 {
5623 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
5624 _("Defaults"),
5625 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
5626 GTK_STOCK_CLEAR );
5627 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
5628 gtk_action_group_add_action( mainActions, act );
5629 gtk_action_set_sensitive( act, TRUE );
5630 }
5632 }
5634 /*
5635 Local Variables:
5636 mode:c++
5637 c-file-style:"stroustrup"
5638 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
5639 indent-tabs-mode:nil
5640 fill-column:99
5641 End:
5642 */
5643 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :