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