3c35d0cfecc767aff62edda8e5ee61dabac172bc
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 "../libnrtype/font-instance.h"
80 #include "../connection-pool.h"
81 #include "../prefs-utils.h"
82 #include "../inkscape-stock.h"
83 #include "icon.h"
84 #include "graphlayout/graphlayout.h"
86 #include "mod360.h"
88 #include "toolbox.h"
90 #include "flood-context.h"
92 #include "ink-action.h"
93 #include "ege-adjustment-action.h"
94 #include "ege-output-action.h"
95 #include "ege-select-one-action.h"
96 #include "helper/unit-tracker.h"
98 using Inkscape::UnitTracker;
100 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
101 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
103 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
104 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
105 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
116 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
122 static struct {
123 gchar const *type_name;
124 gchar const *data_name;
125 sp_verb_t verb;
126 sp_verb_t doubleclick_verb;
127 } const tools[] = {
128 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
129 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
130 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
131 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
132 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
133 { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
134 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
135 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
136 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
137 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
138 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
139 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
140 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
141 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
142 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
143 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
144 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
145 { NULL, NULL, 0, 0 }
146 };
148 static struct {
149 gchar const *type_name;
150 gchar const *data_name;
151 GtkWidget *(*create_func)(SPDesktop *desktop);
152 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
153 gchar const *ui_name;
154 gint swatch_verb_id;
155 gchar const *swatch_tool;
156 gchar const *swatch_tip;
157 } const aux_toolboxes[] = {
158 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
159 SP_VERB_INVALID, 0, 0},
160 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
161 SP_VERB_INVALID, 0, 0},
162 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
163 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", _("Color/opacity used for color tweaking")},
164 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
165 SP_VERB_INVALID, 0, 0},
166 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
167 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
168 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
169 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
170 { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar",
171 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
172 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
173 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
174 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
175 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
176 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
177 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
178 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
179 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
180 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
181 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
182 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
183 SP_VERB_INVALID, 0, 0},
184 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
185 SP_VERB_INVALID, 0, 0},
186 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
187 SP_VERB_INVALID, 0, 0},
188 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
189 SP_VERB_INVALID, 0, 0},
190 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
191 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
192 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
193 };
196 static gchar const * ui_descr =
197 "<ui>"
198 " <toolbar name='SelectToolbar'>"
199 " <toolitem action='EditSelectAll' />"
200 " <toolitem action='EditSelectAllInAllLayers' />"
201 " <toolitem action='EditDeselect' />"
202 " <separator />"
203 " <toolitem action='ObjectRotate90CCW' />"
204 " <toolitem action='ObjectRotate90' />"
205 " <toolitem action='ObjectFlipHorizontally' />"
206 " <toolitem action='ObjectFlipVertically' />"
207 " <separator />"
208 " <toolitem action='SelectionToBack' />"
209 " <toolitem action='SelectionLower' />"
210 " <toolitem action='SelectionRaise' />"
211 " <toolitem action='SelectionToFront' />"
212 " <separator />"
213 " <toolitem action='XAction' />"
214 " <toolitem action='YAction' />"
215 " <toolitem action='WidthAction' />"
216 " <toolitem action='LockAction' />"
217 " <toolitem action='HeightAction' />"
218 " <toolitem action='UnitsAction' />"
219 " <separator />"
220 " <toolitem action='transform_affect_label' />"
221 " <toolitem action='transform_stroke' />"
222 " <toolitem action='transform_corners' />"
223 " <toolitem action='transform_gradient' />"
224 " <toolitem action='transform_pattern' />"
225 " </toolbar>"
227 " <toolbar name='NodeToolbar'>"
228 " <toolitem action='NodeInsertAction' />"
229 " <toolitem action='NodeDeleteAction' />"
230 " <separator />"
231 " <toolitem action='NodeJoinAction' />"
232 " <toolitem action='NodeJoinSegmentAction' />"
233 " <toolitem action='NodeDeleteSegmentAction' />"
234 " <toolitem action='NodeBreakAction' />"
235 " <separator />"
236 " <toolitem action='NodeCuspAction' />"
237 " <toolitem action='NodeSmoothAction' />"
238 " <toolitem action='NodeSymmetricAction' />"
239 " <separator />"
240 " <toolitem action='NodeLineAction' />"
241 " <toolitem action='NodeCurveAction' />"
242 " <separator />"
243 " <toolitem action='ObjectToPath' />"
244 " <toolitem action='StrokeToPath' />"
245 " <separator />"
246 " <toolitem action='NodesShowHandlesAction' />"
247 " <separator />"
248 " <toolitem action='EditNextLPEParameterAction' />"
249 " <separator />"
250 " <toolitem action='NodeXAction' />"
251 " <toolitem action='NodeYAction' />"
252 " <toolitem action='NodeUnitsAction' />"
253 " </toolbar>"
255 " <toolbar name='TweakToolbar'>"
256 " <toolitem action='TweakWidthAction' />"
257 " <separator />"
258 " <toolitem action='TweakForceAction' />"
259 " <toolitem action='TweakPressureAction' />"
260 " <separator />"
261 " <toolitem action='TweakModeAction' />"
262 " <separator />"
263 " <toolitem action='TweakFidelityAction' />"
264 " <separator />"
265 " <toolitem action='TweakChannelsLabel' />"
266 " <toolitem action='TweakDoH' />"
267 " <toolitem action='TweakDoS' />"
268 " <toolitem action='TweakDoL' />"
269 " <toolitem action='TweakDoO' />"
270 " </toolbar>"
272 " <toolbar name='ZoomToolbar'>"
273 " <toolitem action='ZoomIn' />"
274 " <toolitem action='ZoomOut' />"
275 " <separator />"
276 " <toolitem action='Zoom1:0' />"
277 " <toolitem action='Zoom1:2' />"
278 " <toolitem action='Zoom2:1' />"
279 " <separator />"
280 " <toolitem action='ZoomSelection' />"
281 " <toolitem action='ZoomDrawing' />"
282 " <toolitem action='ZoomPage' />"
283 " <toolitem action='ZoomPageWidth' />"
284 " <separator />"
285 " <toolitem action='ZoomPrev' />"
286 " <toolitem action='ZoomNext' />"
287 " </toolbar>"
289 " <toolbar name='StarToolbar'>"
290 " <separator />"
291 " <toolitem action='StarStateAction' />"
292 " <separator />"
293 " <toolitem action='FlatAction' />"
294 " <separator />"
295 " <toolitem action='MagnitudeAction' />"
296 " <toolitem action='SpokeAction' />"
297 " <toolitem action='RoundednessAction' />"
298 " <toolitem action='RandomizationAction' />"
299 " <separator />"
300 " <toolitem action='StarResetAction' />"
301 " </toolbar>"
303 " <toolbar name='RectToolbar'>"
304 " <toolitem action='RectStateAction' />"
305 " <toolitem action='RectWidthAction' />"
306 " <toolitem action='RectHeightAction' />"
307 " <toolitem action='RadiusXAction' />"
308 " <toolitem action='RadiusYAction' />"
309 " <toolitem action='RectUnitsAction' />"
310 " <separator />"
311 " <toolitem action='RectResetAction' />"
312 " </toolbar>"
314 " <toolbar name='3DBoxToolbar'>"
315 " <toolitem action='3DBoxPosAngleXAction' />"
316 " <toolitem action='3DBoxVPXAction' />"
317 " <separator />"
318 " <toolitem action='3DBoxPosAngleYAction' />"
319 " <toolitem action='3DBoxVPYAction' />"
320 " <separator />"
321 " <toolitem action='3DBoxPosAngleZAction' />"
322 " <toolitem action='3DBoxVPZAction' />"
323 " <separator />"
324 " </toolbar>"
326 " <toolbar name='SpiralToolbar'>"
327 " <toolitem action='SpiralStateAction' />"
328 " <toolitem action='SpiralRevolutionAction' />"
329 " <toolitem action='SpiralExpansionAction' />"
330 " <toolitem action='SpiralT0Action' />"
331 " <separator />"
332 " <toolitem action='SpiralResetAction' />"
333 " </toolbar>"
335 " <toolbar name='PenToolbar'>"
336 " </toolbar>"
338 " <toolbar name='PencilToolbar'>"
339 " </toolbar>"
341 " <toolbar name='CalligraphyToolbar'>"
342 " <separator />"
343 " <toolitem action='CalligraphyWidthAction' />"
344 " <toolitem action='PressureAction' />"
345 " <toolitem action='TraceAction' />"
346 " <toolitem action='ThinningAction' />"
347 " <separator />"
348 " <toolitem action='AngleAction' />"
349 " <toolitem action='TiltAction' />"
350 " <toolitem action='FixationAction' />"
351 " <separator />"
352 " <toolitem action='CapRoundingAction' />"
353 " <separator />"
354 " <toolitem action='TremorAction' />"
355 " <toolitem action='WiggleAction' />"
356 " <toolitem action='MassAction' />"
357 " <separator />"
358 " <toolitem action='CalligraphyResetAction' />"
359 " </toolbar>"
361 " <toolbar name='ArcToolbar'>"
362 " <toolitem action='ArcStateAction' />"
363 " <separator />"
364 " <toolitem action='ArcStartAction' />"
365 " <toolitem action='ArcEndAction' />"
366 " <separator />"
367 " <toolitem action='ArcOpenAction' />"
368 " <separator />"
369 " <toolitem action='ArcResetAction' />"
370 " <separator />"
371 " </toolbar>"
373 " <toolbar name='PaintbucketToolbar'>"
374 " <toolitem action='ChannelsAction' />"
375 " <separator />"
376 " <toolitem action='ThresholdAction' />"
377 " <separator />"
378 " <toolitem action='OffsetAction' />"
379 " <toolitem action='PaintbucketUnitsAction' />"
380 " <separator />"
381 " <toolitem action='AutoGapAction' />"
382 " <separator />"
383 " <toolitem action='PaintbucketResetAction' />"
384 " </toolbar>"
386 " <toolbar name='DropperToolbar'>"
387 " <toolitem action='DropperPickAlphaAction' />"
388 " <toolitem action='DropperSetAlphaAction' />"
389 " </toolbar>"
391 " <toolbar name='ConnectorToolbar'>"
392 " <toolitem action='ConnectorAvoidAction' />"
393 " <toolitem action='ConnectorIgnoreAction' />"
394 " <toolitem action='ConnectorSpacingAction' />"
395 " <toolitem action='ConnectorGraphAction' />"
396 " <toolitem action='ConnectorLengthAction' />"
397 " <toolitem action='ConnectorDirectedAction' />"
398 " <toolitem action='ConnectorOverlapAction' />"
399 " </toolbar>"
401 "</ui>"
402 ;
404 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
406 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
408 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
409 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
411 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
412 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
414 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
415 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
417 /* Global text entry widgets necessary for update */
418 /* GtkWidget *dropper_rgb_entry,
419 *dropper_opacity_entry ; */
420 // should be made a private member once this is converted to class
422 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
423 connection->disconnect();
424 delete connection;
425 }
427 static void purge_repr_listener( GObject* obj, GObject* tbl )
428 {
429 (void)obj;
430 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
431 if (oldrepr) { // remove old listener
432 sp_repr_remove_listener_by_data(oldrepr, tbl);
433 Inkscape::GC::release(oldrepr);
434 oldrepr = 0;
435 g_object_set_data( tbl, "repr", NULL );
436 }
437 }
439 GtkWidget *
440 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
441 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
442 Inkscape::UI::View::View *view, GtkTooltips *tt)
443 {
444 SPAction *action = verb->get_action(view);
445 if (!action) return NULL;
447 SPAction *doubleclick_action;
448 if (doubleclick_verb)
449 doubleclick_action = doubleclick_verb->get_action(view);
450 else
451 doubleclick_action = NULL;
453 /* fixme: Handle sensitive/unsensitive */
454 /* fixme: Implement sp_button_new_from_action */
455 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
456 gtk_widget_show(b);
457 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
459 return b;
460 }
462 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
463 Inkscape::UI::View::View *view, GtkTooltips *tt)
464 {
465 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
466 }
468 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
469 Inkscape::UI::View::View *view, GtkTooltips *tt)
470 {
471 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
472 }
475 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
476 {
477 SPAction* targetAction = SP_ACTION(user_data);
478 if ( targetAction ) {
479 sp_action_perform( targetAction, NULL );
480 }
481 }
483 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
484 {
485 if ( data ) {
486 GtkAction* act = GTK_ACTION(data);
487 gtk_action_set_sensitive( act, sensitive );
488 }
489 }
491 static SPActionEventVector action_event_vector = {
492 {NULL},
493 NULL,
494 NULL,
495 sp_action_action_set_sensitive,
496 NULL,
497 NULL
498 };
500 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
501 {
502 GtkAction* act = 0;
504 SPAction* targetAction = verb->get_action(view);
505 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
506 act = GTK_ACTION(inky);
507 gtk_action_set_sensitive( act, targetAction->sensitive );
509 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
511 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
512 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
514 return act;
515 }
517 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
518 {
519 Inkscape::UI::View::View *view = desktop;
520 gint verbsToUse[] = {
521 // disabled until we have icons for them:
522 //find
523 //SP_VERB_EDIT_TILE,
524 //SP_VERB_EDIT_UNTILE,
525 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
526 SP_VERB_DIALOG_DISPLAY,
527 SP_VERB_DIALOG_FILL_STROKE,
528 SP_VERB_DIALOG_NAMEDVIEW,
529 SP_VERB_DIALOG_TEXT,
530 SP_VERB_DIALOG_XML_EDITOR,
531 SP_VERB_EDIT_CLONE,
532 SP_VERB_EDIT_COPY,
533 SP_VERB_EDIT_CUT,
534 SP_VERB_EDIT_DUPLICATE,
535 SP_VERB_EDIT_PASTE,
536 SP_VERB_EDIT_REDO,
537 SP_VERB_EDIT_UNDO,
538 SP_VERB_EDIT_UNLINK_CLONE,
539 SP_VERB_FILE_EXPORT,
540 SP_VERB_FILE_IMPORT,
541 SP_VERB_FILE_NEW,
542 SP_VERB_FILE_OPEN,
543 SP_VERB_FILE_PRINT,
544 SP_VERB_FILE_SAVE,
545 SP_VERB_OBJECT_TO_CURVE,
546 SP_VERB_SELECTION_GROUP,
547 SP_VERB_SELECTION_OUTLINE,
548 SP_VERB_SELECTION_UNGROUP,
549 SP_VERB_ZOOM_1_1,
550 SP_VERB_ZOOM_1_2,
551 SP_VERB_ZOOM_2_1,
552 SP_VERB_ZOOM_DRAWING,
553 SP_VERB_ZOOM_IN,
554 SP_VERB_ZOOM_NEXT,
555 SP_VERB_ZOOM_OUT,
556 SP_VERB_ZOOM_PAGE,
557 SP_VERB_ZOOM_PAGE_WIDTH,
558 SP_VERB_ZOOM_PREV,
559 SP_VERB_ZOOM_SELECTION,
560 };
562 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
563 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
565 static std::map<SPDesktop*, GtkActionGroup*> groups;
566 GtkActionGroup* mainActions = 0;
567 if ( groups.find(desktop) != groups.end() ) {
568 mainActions = groups[desktop];
569 }
571 if ( !mainActions ) {
572 mainActions = gtk_action_group_new("main");
573 groups[desktop] = mainActions;
574 }
576 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
577 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
578 if ( verb ) {
579 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
580 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
581 gtk_action_group_add_action( mainActions, act );
582 }
583 }
584 }
586 return mainActions;
587 }
590 GtkWidget *
591 sp_tool_toolbox_new()
592 {
593 GtkTooltips *tt = gtk_tooltips_new();
594 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
596 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
597 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
599 gtk_widget_set_sensitive(tb, FALSE);
601 GtkWidget *hb = gtk_handle_box_new();
602 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
603 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
604 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
606 gtk_container_add(GTK_CONTAINER(hb), tb);
607 gtk_widget_show(GTK_WIDGET(tb));
609 sigc::connection* conn = new sigc::connection;
610 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
612 return hb;
613 }
615 static void
616 aux_toolbox_attached(GtkHandleBox */*toolbox*/, GtkWidget *child)
617 {
618 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
619 gtk_widget_queue_resize(child);
620 }
622 static void
623 aux_toolbox_detached(GtkHandleBox */*toolbox*/, GtkWidget *child)
624 {
625 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
626 gtk_widget_queue_resize(child);
627 }
629 GtkWidget *
630 sp_aux_toolbox_new()
631 {
632 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
634 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
635 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
636 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
637 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
638 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
640 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
641 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
643 gtk_widget_set_sensitive(tb, FALSE);
645 GtkWidget *hb = gtk_handle_box_new();
646 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
647 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
648 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
650 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
651 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
653 gtk_container_add(GTK_CONTAINER(hb), tb);
654 gtk_widget_show(GTK_WIDGET(tb));
656 sigc::connection* conn = new sigc::connection;
657 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
659 return hb;
660 }
662 //####################################
663 //# Commands Bar
664 //####################################
666 GtkWidget *
667 sp_commands_toolbox_new()
668 {
669 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
671 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
672 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
673 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
674 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
675 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
677 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
678 gtk_widget_set_sensitive(tb, FALSE);
680 GtkWidget *hb = gtk_handle_box_new();
681 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
682 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
683 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
685 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
686 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
688 gtk_container_add(GTK_CONTAINER(hb), tb);
689 gtk_widget_show(GTK_WIDGET(tb));
691 sigc::connection* conn = new sigc::connection;
692 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
694 return hb;
695 }
697 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
698 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
699 gchar const *path, gchar const *data, gdouble def,
700 GtkWidget *focusTarget,
701 GtkWidget *us,
702 GObject *dataKludge,
703 gboolean altx, gchar const *altx_mark,
704 gdouble lower, gdouble upper, gdouble step, gdouble page,
705 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
706 void (*callback)(GtkAdjustment *, GObject *),
707 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
708 {
709 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
710 lower, upper, step, page, page ) );
711 if (us) {
712 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
713 }
715 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
717 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
718 if ( shortLabel ) {
719 g_object_set( act, "short_label", shortLabel, NULL );
720 }
722 if ( (descrCount > 0) && descrLabels && descrValues ) {
723 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
724 }
726 if ( focusTarget ) {
727 ege_adjustment_action_set_focuswidget( act, focusTarget );
728 }
730 if ( altx && altx_mark ) {
731 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
732 }
734 if ( dataKludge ) {
735 g_object_set_data( dataKludge, data, adj );
736 }
738 // Using a cast just to make sure we pass in the right kind of function pointer
739 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
741 return act;
742 }
745 //####################################
746 //# node editing callbacks
747 //####################################
749 /**
750 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
751 */
752 static ShapeEditor *get_current_shape_editor()
753 {
754 if (!SP_ACTIVE_DESKTOP) {
755 return NULL;
756 }
758 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
760 if (!SP_IS_NODE_CONTEXT(event_context)) {
761 return NULL;
762 }
764 return SP_NODE_CONTEXT(event_context)->shape_editor;
765 }
768 void
769 sp_node_path_edit_add(void)
770 {
771 ShapeEditor *shape_editor = get_current_shape_editor();
772 if (shape_editor) shape_editor->add_node();
773 }
775 void
776 sp_node_path_edit_delete(void)
777 {
778 ShapeEditor *shape_editor = get_current_shape_editor();
779 if (shape_editor) shape_editor->delete_nodes();
780 }
782 void
783 sp_node_path_edit_delete_segment(void)
784 {
785 ShapeEditor *shape_editor = get_current_shape_editor();
786 if (shape_editor) shape_editor->delete_segment();
787 }
789 void
790 sp_node_path_edit_break(void)
791 {
792 ShapeEditor *shape_editor = get_current_shape_editor();
793 if (shape_editor) shape_editor->break_at_nodes();
794 }
796 void
797 sp_node_path_edit_join(void)
798 {
799 ShapeEditor *shape_editor = get_current_shape_editor();
800 if (shape_editor) shape_editor->join_nodes();
801 }
803 void
804 sp_node_path_edit_join_segment(void)
805 {
806 ShapeEditor *shape_editor = get_current_shape_editor();
807 if (shape_editor) shape_editor->join_segments();
808 }
810 void
811 sp_node_path_edit_toline(void)
812 {
813 ShapeEditor *shape_editor = get_current_shape_editor();
814 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
815 }
817 void
818 sp_node_path_edit_tocurve(void)
819 {
820 ShapeEditor *shape_editor = get_current_shape_editor();
821 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
822 }
824 void
825 sp_node_path_edit_cusp(void)
826 {
827 ShapeEditor *shape_editor = get_current_shape_editor();
828 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
829 }
831 void
832 sp_node_path_edit_smooth(void)
833 {
834 ShapeEditor *shape_editor = get_current_shape_editor();
835 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
836 }
838 void
839 sp_node_path_edit_symmetrical(void)
840 {
841 ShapeEditor *shape_editor = get_current_shape_editor();
842 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
843 }
845 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
846 bool show = gtk_toggle_action_get_active( act );
847 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
848 ShapeEditor *shape_editor = get_current_shape_editor();
849 if (shape_editor) shape_editor->show_handles(show);
850 }
852 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
853 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
854 }
856 /* is called when the node selection is modified */
857 static void
858 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
859 {
860 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
861 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
862 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
863 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
865 // quit if run by the attr_changed listener
866 if (g_object_get_data( tbl, "freeze" )) {
867 return;
868 }
870 // in turn, prevent listener from responding
871 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
873 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
874 SPUnit const *unit = tracker->getActiveUnit();
876 ShapeEditor *shape_editor = get_current_shape_editor();
877 if (shape_editor && shape_editor->has_nodepath()) {
878 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
879 int n_selected = 0;
880 if (nodepath) {
881 n_selected = nodepath->numSelected();
882 }
884 if (n_selected == 0) {
885 gtk_action_set_sensitive(xact, FALSE);
886 gtk_action_set_sensitive(yact, FALSE);
887 } else {
888 gtk_action_set_sensitive(xact, TRUE);
889 gtk_action_set_sensitive(yact, TRUE);
890 NR::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
891 NR::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
893 if (n_selected == 1) {
894 NR::Point sel_node = nodepath->singleSelectedCoords();
895 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
896 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[NR::X], *unit));
897 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[NR::Y], *unit));
898 }
899 } else {
900 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
901 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
902 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
903 /* Note: Currently x and y will always have a value, even if the coordinates of the
904 selected nodes don't coincide (in this case we use the coordinates of the center
905 of the bounding box). So the entries are never set to zero. */
906 // FIXME: Maybe we should clear the entry if several nodes are selected
907 // instead of providing a kind of average value
908 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
909 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
910 }
911 }
912 }
913 } else {
914 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
915 gtk_action_set_sensitive(xact, FALSE);
916 gtk_action_set_sensitive(yact, FALSE);
917 }
919 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
920 }
922 static void
923 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
924 {
925 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
927 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
928 SPUnit const *unit = tracker->getActiveUnit();
930 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
931 prefs_set_double_attribute("tools.nodes", value_name, sp_units_get_pixels(adj->value, *unit));
932 }
934 // quit if run by the attr_changed listener
935 if (g_object_get_data( tbl, "freeze" )) {
936 return;
937 }
939 // in turn, prevent listener from responding
940 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
942 ShapeEditor *shape_editor = get_current_shape_editor();
943 if (shape_editor && shape_editor->has_nodepath()) {
944 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
945 if (!strcmp(value_name, "x")) {
946 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::X);
947 }
948 if (!strcmp(value_name, "y")) {
949 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::Y);
950 }
951 }
953 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
954 }
956 static void
957 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
958 {
959 sp_node_path_value_changed(adj, tbl, "x");
960 }
962 static void
963 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
964 {
965 sp_node_path_value_changed(adj, tbl, "y");
966 }
968 //################################
969 //## Node Editing Toolbox ##
970 //################################
972 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
973 {
974 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
975 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
976 g_object_set_data( holder, "tracker", tracker );
978 {
979 InkAction* inky = ink_action_new( "NodeInsertAction",
980 _("Insert node"),
981 _("Insert new nodes into selected segments"),
982 "node_insert",
983 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
984 g_object_set( inky, "short_label", _("Insert"), NULL );
985 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
986 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
987 }
989 {
990 InkAction* inky = ink_action_new( "NodeDeleteAction",
991 _("Delete node"),
992 _("Delete selected nodes"),
993 "node_delete",
994 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
995 g_object_set( inky, "short_label", _("Delete"), NULL );
996 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
997 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
998 }
1000 {
1001 InkAction* inky = ink_action_new( "NodeJoinAction",
1002 _("Join endnodes"),
1003 _("Join selected endnodes"),
1004 "node_join",
1005 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1006 g_object_set( inky, "short_label", _("Join"), NULL );
1007 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1008 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1009 }
1011 {
1012 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1013 _("Join Segment"),
1014 _("Join selected endnodes with a new segment"),
1015 "node_join_segment",
1016 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1017 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1018 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1019 }
1021 {
1022 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1023 _("Delete Segment"),
1024 _("Split path between two non-endpoint nodes"),
1025 "node_delete_segment",
1026 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1027 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1028 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1029 }
1031 {
1032 InkAction* inky = ink_action_new( "NodeBreakAction",
1033 _("Node Break"),
1034 _("Break path at selected nodes"),
1035 "node_break",
1036 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1037 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1038 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1039 }
1041 {
1042 InkAction* inky = ink_action_new( "NodeCuspAction",
1043 _("Node Cusp"),
1044 _("Make selected nodes corner"),
1045 "node_cusp",
1046 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1047 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1048 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1049 }
1051 {
1052 InkAction* inky = ink_action_new( "NodeSmoothAction",
1053 _("Node Smooth"),
1054 _("Make selected nodes smooth"),
1055 "node_smooth",
1056 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1057 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1058 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1059 }
1061 {
1062 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1063 _("Node Symmetric"),
1064 _("Make selected nodes symmetric"),
1065 "node_symmetric",
1066 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1067 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1068 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1069 }
1071 {
1072 InkAction* inky = ink_action_new( "NodeLineAction",
1073 _("Node Line"),
1074 _("Make selected segments lines"),
1075 "node_line",
1076 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1077 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1078 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1079 }
1081 {
1082 InkAction* inky = ink_action_new( "NodeCurveAction",
1083 _("Node Curve"),
1084 _("Make selected segments curves"),
1085 "node_curve",
1086 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1087 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1088 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1089 }
1091 {
1092 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1093 _("Show Handles"),
1094 _("Show the Bezier handles of selected nodes"),
1095 "nodes_show_handles",
1096 Inkscape::ICON_SIZE_DECORATION );
1097 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1098 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1099 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1100 }
1102 {
1103 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1104 _("Next Path Effect Parameter"),
1105 _("Show next Path Effect parameter for editing"),
1106 "edit_next_parameter",
1107 Inkscape::ICON_SIZE_DECORATION );
1108 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1109 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1110 }
1112 /* X coord of selected node(s) */
1113 {
1114 EgeAdjustmentAction* eact = 0;
1115 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1116 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1117 eact = create_adjustment_action( "NodeXAction",
1118 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1119 "tools.nodes", "Xcoord", 0,
1120 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1121 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1122 labels, values, G_N_ELEMENTS(labels),
1123 sp_node_path_x_value_changed );
1124 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1125 g_object_set_data( holder, "nodes_x_action", eact );
1126 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1127 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1128 }
1130 /* Y coord of selected node(s) */
1131 {
1132 EgeAdjustmentAction* eact = 0;
1133 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1134 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1135 eact = create_adjustment_action( "NodeYAction",
1136 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1137 "tools.nodes", "Ycoord", 0,
1138 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1139 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1140 labels, values, G_N_ELEMENTS(labels),
1141 sp_node_path_y_value_changed );
1142 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1143 g_object_set_data( holder, "nodes_y_action", eact );
1144 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1145 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1146 }
1148 // add the units menu
1149 {
1150 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1151 gtk_action_group_add_action( mainActions, act );
1152 }
1154 sigc::connection *connection = new sigc::connection (
1155 desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(sp_node_toolbox_coord_changed), (GObject *)holder))
1156 );
1158 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1159 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1160 } // end of sp_node_toolbox_prep()
1163 //########################
1164 //## Zoom Toolbox ##
1165 //########################
1167 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1168 {
1169 // no custom GtkAction setup needed
1170 } // end of sp_zoom_toolbox_prep()
1172 void
1173 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1174 {
1175 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")));
1176 }
1179 void
1180 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1181 {
1182 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")));
1183 }
1185 void
1186 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1187 {
1188 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")));
1189 }
1191 static void
1192 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1193 {
1194 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1195 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1197 if (old_desktop) {
1198 GList *children, *iter;
1200 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1201 for ( iter = children ; iter ; iter = iter->next ) {
1202 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1203 }
1204 g_list_free(children);
1205 }
1207 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1209 if (desktop) {
1210 gtk_widget_set_sensitive(toolbox, TRUE);
1211 setup_func(toolbox, desktop);
1212 update_func(desktop, desktop->event_context, toolbox);
1213 *conn = desktop->connectEventContextChanged
1214 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1215 } else {
1216 gtk_widget_set_sensitive(toolbox, FALSE);
1217 }
1219 } // end of toolbox_set_desktop()
1222 static void
1223 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1224 {
1225 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
1226 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
1227 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
1228 // "toolbox.tools" was not set. Fallback to older value
1229 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
1231 // Copy the setting forwards
1232 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
1233 }
1234 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1236 for (int i = 0 ; tools[i].type_name ; i++ ) {
1237 GtkWidget *button =
1238 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
1239 SP_BUTTON_TYPE_TOGGLE,
1240 Inkscape::Verb::get(tools[i].verb),
1241 Inkscape::Verb::get(tools[i].doubleclick_verb),
1242 desktop,
1243 tooltips );
1245 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1246 (gpointer)button );
1247 }
1248 }
1251 static void
1252 update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
1253 {
1254 gchar const *const tname = ( eventcontext
1255 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1256 : NULL );
1257 for (int i = 0 ; tools[i].type_name ; i++ ) {
1258 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1259 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1260 }
1261 }
1263 static void
1264 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1265 {
1266 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1267 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1268 GtkUIManager* mgr = gtk_ui_manager_new();
1269 GError* errVal = 0;
1270 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1271 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1273 std::map<std::string, GtkWidget*> dataHolders;
1275 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1276 if ( aux_toolboxes[i].prep_func ) {
1277 // converted to GtkActions and UIManager
1279 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1280 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1281 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1282 dataHolders[aux_toolboxes[i].type_name] = kludge;
1283 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1284 } else {
1286 GtkWidget *sub_toolbox = 0;
1287 if (aux_toolboxes[i].create_func == NULL)
1288 sub_toolbox = sp_empty_toolbox_new(desktop);
1289 else {
1290 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1291 }
1293 gtk_size_group_add_widget( grouper, sub_toolbox );
1295 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1296 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1298 }
1299 }
1301 // Second pass to create toolbars *after* all GtkActions are created
1302 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1303 if ( aux_toolboxes[i].prep_func ) {
1304 // converted to GtkActions and UIManager
1306 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1308 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1309 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1311 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1312 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1313 g_free( tmp );
1314 tmp = 0;
1316 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1317 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1318 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1319 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1320 }
1321 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1324 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1326 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1327 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1328 swatch->setDesktop( desktop );
1329 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1330 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1331 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1332 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 );
1333 }
1335 gtk_widget_show_all( holder );
1336 sp_set_font_size_smaller( holder );
1338 gtk_size_group_add_widget( grouper, holder );
1340 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1341 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1342 }
1343 }
1345 g_object_unref( G_OBJECT(grouper) );
1346 }
1348 static void
1349 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1350 {
1351 gchar const *tname = ( eventcontext
1352 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1353 : NULL );
1354 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1355 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1356 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1357 gtk_widget_show_all(sub_toolbox);
1358 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1359 } else {
1360 gtk_widget_hide(sub_toolbox);
1361 }
1362 }
1363 }
1365 static void
1366 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1367 {
1368 gchar const * descr =
1369 "<ui>"
1370 " <toolbar name='CommandsToolbar'>"
1371 " <toolitem action='FileNew' />"
1372 " <toolitem action='FileOpen' />"
1373 " <toolitem action='FileSave' />"
1374 " <toolitem action='FilePrint' />"
1375 " <separator />"
1376 " <toolitem action='FileImport' />"
1377 " <toolitem action='FileExport' />"
1378 " <separator />"
1379 " <toolitem action='EditUndo' />"
1380 " <toolitem action='EditRedo' />"
1381 " <separator />"
1382 " <toolitem action='EditCopy' />"
1383 " <toolitem action='EditCut' />"
1384 " <toolitem action='EditPaste' />"
1385 " <separator />"
1386 " <toolitem action='ZoomSelection' />"
1387 " <toolitem action='ZoomDrawing' />"
1388 " <toolitem action='ZoomPage' />"
1389 " <separator />"
1390 " <toolitem action='EditDuplicate' />"
1391 " <toolitem action='EditClone' />"
1392 " <toolitem action='EditUnlinkClone' />"
1393 " <separator />"
1394 " <toolitem action='SelectionGroup' />"
1395 " <toolitem action='SelectionUnGroup' />"
1396 " <separator />"
1397 " <toolitem action='DialogFillStroke' />"
1398 " <toolitem action='DialogText' />"
1399 " <toolitem action='DialogXMLEditor' />"
1400 " <toolitem action='DialogAlignDistribute' />"
1401 " <separator />"
1402 " <toolitem action='DialogPreferences' />"
1403 " <toolitem action='DialogDocumentProperties' />"
1404 " </toolbar>"
1405 "</ui>";
1406 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1409 GtkUIManager* mgr = gtk_ui_manager_new();
1410 GError* errVal = 0;
1412 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1413 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1415 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1416 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1417 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1418 }
1419 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1420 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1421 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1424 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1425 }
1427 static void
1428 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1429 {
1430 }
1432 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1433 {
1434 gtk_widget_show(toolbox_toplevel);
1435 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1437 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1438 if (!shown_toolbox) {
1439 return;
1440 }
1441 gtk_widget_show(toolbox);
1443 // need to show the spacer, or the padding will be off
1444 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1445 gtk_widget_show(spacer);
1447 gtk_widget_show_all(shown_toolbox);
1448 }
1450 void
1451 aux_toolbox_space(GtkWidget *tb, gint space)
1452 {
1453 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1454 }
1456 static GtkWidget *
1457 sp_empty_toolbox_new(SPDesktop *desktop)
1458 {
1459 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1460 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1461 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1463 gtk_widget_show_all(tbl);
1464 sp_set_font_size_smaller (tbl);
1466 return tbl;
1467 }
1469 // helper UI functions
1471 GtkWidget *
1472 sp_tb_spinbutton(
1473 gchar *label, gchar const *tooltip,
1474 gchar const *path, gchar const *data, gdouble def,
1475 GtkWidget *us,
1476 GtkWidget *tbl,
1477 gboolean altx, gchar const *altx_mark,
1478 gdouble lower, gdouble upper, gdouble step, gdouble page,
1479 void (*callback)(GtkAdjustment *, GtkWidget *),
1480 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1481 {
1482 GtkTooltips *tt = gtk_tooltips_new();
1484 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1486 GtkWidget *l = gtk_label_new(label);
1487 gtk_widget_show(l);
1488 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1489 gtk_container_add(GTK_CONTAINER(hb), l);
1491 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1492 lower, upper, step, page, page);
1493 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1494 if (us)
1495 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1497 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1498 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1499 if (altx)
1500 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1501 gtk_widget_set_size_request(sb,
1502 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1503 AUX_SPINBUTTON_HEIGHT);
1504 gtk_widget_show(sb);
1505 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1506 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1507 gtk_container_add(GTK_CONTAINER(hb), sb);
1508 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1510 return hb;
1511 }
1513 #define MODE_LABEL_WIDTH 70
1515 //########################
1516 //## Star ##
1517 //########################
1519 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1520 {
1521 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1523 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1524 // do not remember prefs if this call is initiated by an undo change, because undoing object
1525 // creation sets bogus values to its attributes before it is deleted
1526 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1527 }
1529 // quit if run by the attr_changed listener
1530 if (g_object_get_data( dataKludge, "freeze" )) {
1531 return;
1532 }
1534 // in turn, prevent listener from responding
1535 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1537 bool modmade = false;
1539 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1540 GSList const *items = selection->itemList();
1541 for (; items != NULL; items = items->next) {
1542 if (SP_IS_STAR((SPItem *) items->data)) {
1543 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1544 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1545 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1546 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1547 + M_PI / (gint)adj->value));
1548 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1549 modmade = true;
1550 }
1551 }
1552 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1553 _("Star: Change number of corners"));
1555 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1556 }
1558 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1559 {
1560 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1562 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1563 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1564 }
1566 // quit if run by the attr_changed listener
1567 if (g_object_get_data( dataKludge, "freeze" )) {
1568 return;
1569 }
1571 // in turn, prevent listener from responding
1572 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1574 bool modmade = false;
1575 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1576 GSList const *items = selection->itemList();
1577 for (; items != NULL; items = items->next) {
1578 if (SP_IS_STAR((SPItem *) items->data)) {
1579 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1581 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1582 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1583 if (r2 < r1) {
1584 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1585 } else {
1586 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1587 }
1589 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1590 modmade = true;
1591 }
1592 }
1594 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1595 _("Star: Change spoke ratio"));
1597 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1598 }
1600 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1601 {
1602 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1603 bool flat = ege_select_one_action_get_active( act ) == 0;
1605 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1606 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1607 flat ? "true" : "false" );
1608 }
1610 // quit if run by the attr_changed listener
1611 if (g_object_get_data( dataKludge, "freeze" )) {
1612 return;
1613 }
1615 // in turn, prevent listener from responding
1616 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1618 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1619 GSList const *items = selection->itemList();
1620 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1621 bool modmade = false;
1623 if ( prop_action ) {
1624 gtk_action_set_sensitive( prop_action, !flat );
1625 }
1627 for (; items != NULL; items = items->next) {
1628 if (SP_IS_STAR((SPItem *) items->data)) {
1629 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1630 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1631 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1632 modmade = true;
1633 }
1634 }
1636 if (modmade) {
1637 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1638 flat ? _("Make polygon") : _("Make star"));
1639 }
1641 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1642 }
1644 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1645 {
1646 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1648 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1649 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1650 }
1652 // quit if run by the attr_changed listener
1653 if (g_object_get_data( dataKludge, "freeze" )) {
1654 return;
1655 }
1657 // in turn, prevent listener from responding
1658 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1660 bool modmade = false;
1662 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1663 GSList const *items = selection->itemList();
1664 for (; items != NULL; items = items->next) {
1665 if (SP_IS_STAR((SPItem *) items->data)) {
1666 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1667 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1668 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1669 modmade = true;
1670 }
1671 }
1672 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1673 _("Star: Change rounding"));
1675 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1676 }
1678 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1679 {
1680 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1682 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1683 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1684 }
1686 // quit if run by the attr_changed listener
1687 if (g_object_get_data( dataKludge, "freeze" )) {
1688 return;
1689 }
1691 // in turn, prevent listener from responding
1692 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1694 bool modmade = false;
1696 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1697 GSList const *items = selection->itemList();
1698 for (; items != NULL; items = items->next) {
1699 if (SP_IS_STAR((SPItem *) items->data)) {
1700 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1701 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1702 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1703 modmade = true;
1704 }
1705 }
1706 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1707 _("Star: Change randomization"));
1709 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1710 }
1713 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1714 gchar const */*old_value*/, gchar const */*new_value*/,
1715 bool /*is_interactive*/, gpointer data)
1716 {
1717 GtkWidget *tbl = GTK_WIDGET(data);
1719 // quit if run by the _changed callbacks
1720 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1721 return;
1722 }
1724 // in turn, prevent callbacks from responding
1725 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1727 GtkAdjustment *adj = 0;
1729 if (!strcmp(name, "inkscape:randomized")) {
1730 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1731 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1732 } else if (!strcmp(name, "inkscape:rounded")) {
1733 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1734 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1735 } else if (!strcmp(name, "inkscape:flatsided")) {
1736 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1737 char const *flatsides = repr->attribute("inkscape:flatsided");
1738 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1739 if ( flatsides && !strcmp(flatsides,"false") ) {
1740 ege_select_one_action_set_active( flat_action, 1 );
1741 gtk_action_set_sensitive( prop_action, TRUE );
1742 } else {
1743 ege_select_one_action_set_active( flat_action, 0 );
1744 gtk_action_set_sensitive( prop_action, FALSE );
1745 }
1746 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1747 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1748 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1749 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1750 if (r2 < r1) {
1751 gtk_adjustment_set_value(adj, r2/r1);
1752 } else {
1753 gtk_adjustment_set_value(adj, r1/r2);
1754 }
1755 } else if (!strcmp(name, "sodipodi:sides")) {
1756 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1757 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1758 }
1760 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1761 }
1764 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1765 {
1766 NULL, /* child_added */
1767 NULL, /* child_removed */
1768 star_tb_event_attr_changed,
1769 NULL, /* content_changed */
1770 NULL /* order_changed */
1771 };
1774 /**
1775 * \param selection Should not be NULL.
1776 */
1777 static void
1778 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1779 {
1780 int n_selected = 0;
1781 Inkscape::XML::Node *repr = NULL;
1783 purge_repr_listener( tbl, tbl );
1785 for (GSList const *items = selection->itemList();
1786 items != NULL;
1787 items = items->next)
1788 {
1789 if (SP_IS_STAR((SPItem *) items->data)) {
1790 n_selected++;
1791 repr = SP_OBJECT_REPR((SPItem *) items->data);
1792 }
1793 }
1795 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1797 if (n_selected == 0) {
1798 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1799 } else if (n_selected == 1) {
1800 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1802 if (repr) {
1803 g_object_set_data( tbl, "repr", repr );
1804 Inkscape::GC::anchor(repr);
1805 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1806 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1807 }
1808 } else {
1809 // FIXME: implement averaging of all parameters for multiple selected stars
1810 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1811 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1812 }
1813 }
1816 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
1817 {
1818 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1819 // callbacks to lump all the changes for all selected objects in one undo step
1821 GtkAdjustment *adj = 0;
1823 // fixme: make settable in prefs!
1824 gint mag = 5;
1825 gdouble prop = 0.5;
1826 gboolean flat = FALSE;
1827 gdouble randomized = 0;
1828 gdouble rounded = 0;
1830 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1831 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1833 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1834 gtk_action_set_sensitive( sb2, !flat );
1836 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1837 gtk_adjustment_set_value(adj, mag);
1838 gtk_adjustment_value_changed(adj);
1840 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1841 gtk_adjustment_set_value(adj, prop);
1842 gtk_adjustment_value_changed(adj);
1844 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1845 gtk_adjustment_set_value(adj, rounded);
1846 gtk_adjustment_value_changed(adj);
1848 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1849 gtk_adjustment_set_value(adj, randomized);
1850 gtk_adjustment_value_changed(adj);
1851 }
1854 void
1855 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1856 {
1857 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1858 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1859 GtkWidget *l = gtk_label_new(NULL);
1860 gtk_label_set_markup(GTK_LABEL(l), title);
1861 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1862 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1863 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1864 }
1867 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1868 {
1869 {
1870 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1871 ege_output_action_set_use_markup( act, TRUE );
1872 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1873 g_object_set_data( holder, "mode_action", act );
1874 }
1876 {
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::VP_INFINITE : Proj::VP_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_fontspec =
3953 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
3955 int result_family =
3956 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3958 int result_style =
3959 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3961 int result_numbers =
3962 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3964 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3966 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3967 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3968 {
3969 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3971 if (repr)
3972 {
3973 sp_style_read_from_repr (query, repr);
3974 }
3975 else
3976 {
3977 return;
3978 }
3979 }
3981 if (query->text)
3982 {
3983 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3984 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3985 gtk_entry_set_text (GTK_ENTRY (entry), "");
3987 } else if (query->text->font_specification.value || query->text->font_family.value) {
3989 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3991 // Get the font that corresponds
3992 Glib::ustring familyName;
3994 font_instance * font = font_factory::Default()->FaceFromStyle(query);
3995 if (font) {
3996 familyName = font_factory::Default()->GetUIFamilyString(font->descr);
3997 font->Unref();
3998 font = NULL;
3999 }
4001 gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
4003 Gtk::TreePath path;
4004 try {
4005 path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
4006 } catch (...) {
4007 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
4008 return;
4009 }
4011 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4012 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4014 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
4016 gtk_tree_selection_select_path (tselection, path.gobj());
4017 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4019 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
4020 }
4022 //Size
4023 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4024 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
4025 g_object_set_data (tbl, "size-block", gpointer(1));
4026 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
4027 g_object_set_data (tbl, "size-block", gpointer(0));
4028 free (str);
4030 //Anchor
4031 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
4032 {
4033 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
4034 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4035 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4036 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4037 }
4038 else
4039 {
4040 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
4041 {
4042 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
4043 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4044 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4045 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4046 }
4047 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
4048 {
4049 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
4050 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4051 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4052 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4053 }
4054 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
4055 {
4056 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
4057 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4058 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4059 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4060 }
4061 }
4063 //Style
4064 {
4065 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
4067 gboolean active = gtk_toggle_button_get_active (button);
4068 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
4070 if (active != check)
4071 {
4072 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4073 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4074 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4075 }
4076 }
4078 {
4079 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
4081 gboolean active = gtk_toggle_button_get_active (button);
4082 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
4084 if (active != check)
4085 {
4086 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4087 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4088 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4089 }
4090 }
4092 //Orientation
4093 //locking both buttons, changing one affect all group (both)
4094 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
4095 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4097 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
4098 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
4100 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
4101 {
4102 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4103 }
4104 else
4105 {
4106 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
4107 }
4108 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4109 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
4110 }
4112 sp_style_unref(query);
4113 }
4115 void
4116 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
4117 {
4118 sp_text_toolbox_selection_changed (selection, tbl);
4119 }
4121 void
4122 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4123 {
4124 sp_text_toolbox_selection_changed (NULL, tbl);
4125 }
4127 void
4128 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4129 GObject *tbl)
4130 {
4131 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4132 GtkTreeModel *model = 0;
4133 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4134 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4135 GtkTreeIter iter;
4136 char *family = 0;
4138 (void)popdown;
4140 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4141 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4143 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
4144 return;
4145 }
4147 gtk_tree_model_get (model, &iter, 0, &family, -1);
4149 if (g_object_get_data (G_OBJECT (selection), "block"))
4150 {
4151 gtk_entry_set_text (GTK_ENTRY (entry), family);
4152 return;
4153 }
4155 gtk_entry_set_text (GTK_ENTRY (entry), family);
4157 SPStyle *query =
4158 sp_style_new (SP_ACTIVE_DOCUMENT);
4160 int result_fontspec =
4161 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4163 SPCSSAttr *css = sp_repr_css_attr_new ();
4165 std::string fontSpec = query->text->font_specification.value;
4166 if (!fontSpec.empty()) {
4167 Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
4168 if (!newFontSpec.empty() && fontSpec != newFontSpec) {
4169 font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
4170 if (font) {
4171 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
4173 // Set all the these just in case they were altered when finding the best
4174 // match for the new family and old style...
4176 gchar c[256];
4178 font->Family(c, 256);
4179 sp_repr_css_set_property (css, "font-family", c);
4181 font->Attribute( "weight", c, 256);
4182 sp_repr_css_set_property (css, "font-weight", c);
4184 font->Attribute("style", c, 256);
4185 sp_repr_css_set_property (css, "font-style", c);
4187 font->Attribute("stretch", c, 256);
4188 sp_repr_css_set_property (css, "font-stretch", c);
4190 font->Attribute("variant", c, 256);
4191 sp_repr_css_set_property (css, "font-variant", c);
4193 font->Unref();
4194 }
4195 }
4196 }
4198 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4199 if (result_fontspec == QUERY_STYLE_NOTHING)
4200 {
4201 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4202 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
4203 }
4204 else
4205 {
4206 sp_desktop_set_style (desktop, css, true, true);
4207 }
4209 sp_style_unref(query);
4211 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4212 _("Text: Change font family"));
4213 sp_repr_css_attr_unref (css);
4214 free (family);
4215 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4217 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4218 }
4220 void
4221 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
4222 GObject *tbl)
4223 {
4224 const char *family = gtk_entry_get_text (entry);
4226 try {
4227 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
4228 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4229 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4230 gtk_tree_selection_select_path (selection, path.gobj());
4231 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4232 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4233 } catch (...) {
4234 if (family && strlen (family))
4235 {
4236 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4237 }
4238 }
4239 }
4241 void
4242 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
4243 gpointer data)
4244 {
4245 if (g_object_get_data (G_OBJECT (button), "block")) return;
4246 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
4247 int prop = GPOINTER_TO_INT(data);
4249 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4250 SPCSSAttr *css = sp_repr_css_attr_new ();
4252 switch (prop)
4253 {
4254 case 0:
4255 {
4256 sp_repr_css_set_property (css, "text-anchor", "start");
4257 sp_repr_css_set_property (css, "text-align", "start");
4258 break;
4259 }
4260 case 1:
4261 {
4262 sp_repr_css_set_property (css, "text-anchor", "middle");
4263 sp_repr_css_set_property (css, "text-align", "center");
4264 break;
4265 }
4267 case 2:
4268 {
4269 sp_repr_css_set_property (css, "text-anchor", "end");
4270 sp_repr_css_set_property (css, "text-align", "end");
4271 break;
4272 }
4274 case 3:
4275 {
4276 sp_repr_css_set_property (css, "text-anchor", "start");
4277 sp_repr_css_set_property (css, "text-align", "justify");
4278 break;
4279 }
4280 }
4282 SPStyle *query =
4283 sp_style_new (SP_ACTIVE_DOCUMENT);
4284 int result_numbers =
4285 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4287 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4288 if (result_numbers == QUERY_STYLE_NOTHING)
4289 {
4290 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4291 }
4293 sp_style_unref(query);
4295 sp_desktop_set_style (desktop, css, true, true);
4296 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4297 _("Text: Change alignment"));
4298 sp_repr_css_attr_unref (css);
4300 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4301 }
4303 void
4304 sp_text_toolbox_style_toggled (GtkToggleButton *button,
4305 gpointer data)
4306 {
4307 if (g_object_get_data (G_OBJECT (button), "block")) return;
4309 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4310 SPCSSAttr *css = sp_repr_css_attr_new ();
4311 int prop = GPOINTER_TO_INT(data);
4312 bool active = gtk_toggle_button_get_active (button);
4314 SPStyle *query =
4315 sp_style_new (SP_ACTIVE_DOCUMENT);
4316 int result_fontspec =
4317 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4319 Glib::ustring fontSpec = query->text->font_specification.value;
4320 Glib::ustring newFontSpec;
4322 switch (prop)
4323 {
4324 case 0:
4325 {
4326 if (!fontSpec.empty()) {
4327 newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
4328 }
4329 if (fontSpec != newFontSpec) {
4330 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
4331 }
4332 break;
4333 }
4335 case 1:
4336 {
4337 if (!fontSpec.empty()) {
4338 newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
4339 }
4340 if (fontSpec != newFontSpec) {
4341 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
4342 }
4343 break;
4344 }
4345 }
4347 if (!fontSpec.empty()) {
4348 sp_repr_css_set_property (css, "-inkscape-font-specification", fontSpec.c_str());
4349 }
4351 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4352 if (result_fontspec == QUERY_STYLE_NOTHING)
4353 {
4354 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4355 }
4357 sp_style_unref(query);
4359 sp_desktop_set_style (desktop, css, true, true);
4360 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4361 _("Text: Change font style"));
4362 sp_repr_css_attr_unref (css);
4364 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4365 }
4367 void
4368 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
4369 gpointer data)
4370 {
4371 if (g_object_get_data (G_OBJECT (button), "block")) {
4372 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4373 return;
4374 }
4376 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4377 SPCSSAttr *css = sp_repr_css_attr_new ();
4378 int prop = GPOINTER_TO_INT(data);
4380 switch (prop)
4381 {
4382 case 0:
4383 {
4384 sp_repr_css_set_property (css, "writing-mode", "lr");
4385 break;
4386 }
4388 case 1:
4389 {
4390 sp_repr_css_set_property (css, "writing-mode", "tb");
4391 break;
4392 }
4393 }
4395 SPStyle *query =
4396 sp_style_new (SP_ACTIVE_DOCUMENT);
4397 int result_numbers =
4398 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4400 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4401 if (result_numbers == QUERY_STYLE_NOTHING)
4402 {
4403 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4404 }
4406 sp_desktop_set_style (desktop, css, true, true);
4407 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4408 _("Text: Change orientation"));
4409 sp_repr_css_attr_unref (css);
4411 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4412 }
4414 gboolean
4415 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, gpointer /*data*/)
4416 {
4417 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4418 if (!desktop) return FALSE;
4420 switch (get_group0_keyval (event)) {
4421 case GDK_Escape: // defocus
4422 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4423 return TRUE; // I consumed the event
4424 break;
4425 case GDK_Return: // defocus
4426 case GDK_KP_Enter:
4427 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4428 return TRUE; // I consumed the event
4429 break;
4430 }
4431 return FALSE;
4432 }
4434 gboolean
4435 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4436 {
4437 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4438 if (!desktop) return FALSE;
4440 switch (get_group0_keyval (event)) {
4441 case GDK_Escape: // defocus
4442 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4443 sp_text_toolbox_selection_changed (NULL, tbl); // update
4444 return TRUE; // I consumed the event
4445 break;
4446 }
4447 return FALSE;
4448 }
4450 gboolean
4451 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
4452 {
4453 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4454 if (!desktop) return FALSE;
4456 switch (get_group0_keyval (event)) {
4457 case GDK_KP_Enter:
4458 case GDK_Return:
4459 case GDK_Escape: // defocus
4460 gtk_widget_hide (w);
4461 visible = false;
4462 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4463 return TRUE; // I consumed the event
4464 break;
4465 }
4466 return FALSE;
4467 }
4470 void
4471 sp_text_toolbox_size_changed (GtkComboBox *cbox,
4472 GObject *tbl)
4473 {
4474 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4476 if (g_object_get_data (tbl, "size-block")) return;
4478 char *text = gtk_combo_box_get_active_text (cbox);
4480 SPCSSAttr *css = sp_repr_css_attr_new ();
4481 sp_repr_css_set_property (css, "font-size", text);
4482 free (text);
4484 SPStyle *query =
4485 sp_style_new (SP_ACTIVE_DOCUMENT);
4486 int result_numbers =
4487 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4489 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4490 if (result_numbers == QUERY_STYLE_NOTHING)
4491 {
4492 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4493 }
4495 sp_style_unref(query);
4497 sp_desktop_set_style (desktop, css, true, true);
4498 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
4499 _("Text: Change font size"));
4500 sp_repr_css_attr_unref (css);
4503 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
4504 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4505 }
4507 void
4508 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
4509 GObject *tbl)
4510 {
4511 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4512 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4513 int x, y;
4515 if (!visible)
4516 {
4517 gdk_window_get_origin (widget->window, &x, &y);
4518 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
4519 gtk_widget_show_all (popdown);
4521 gdk_pointer_grab (widget->window, TRUE,
4522 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
4523 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
4524 GDK_POINTER_MOTION_MASK),
4525 NULL, NULL, GDK_CURRENT_TIME);
4527 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
4529 visible = true;
4530 }
4531 else
4532 {
4533 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4534 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4535 gtk_widget_hide (popdown);
4536 visible = false;
4537 }
4538 }
4540 gboolean
4541 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
4542 GdkEventFocus */*event*/,
4543 GObject */*tbl*/)
4544 {
4545 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
4546 return FALSE;
4547 }
4549 gboolean
4550 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
4551 GdkEventFocus */*event*/,
4552 GObject */*tbl*/)
4553 {
4554 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4556 gtk_widget_hide (popdown);
4557 visible = false;
4558 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4559 return TRUE;
4560 }
4562 void
4563 cell_data_func (GtkTreeViewColumn */*column*/,
4564 GtkCellRenderer *cell,
4565 GtkTreeModel *tree_model,
4566 GtkTreeIter *iter,
4567 gpointer /*data*/)
4568 {
4569 char *family,
4570 *family_escaped,
4571 *sample_escaped;
4573 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
4575 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
4577 family_escaped = g_markup_escape_text (family, -1);
4578 sample_escaped = g_markup_escape_text (sample, -1);
4580 std::stringstream markup;
4581 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
4582 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
4584 free (family);
4585 free (family_escaped);
4586 free (sample_escaped);
4587 }
4589 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
4590 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
4591 if (completion) {
4592 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
4593 g_object_unref (completion);
4594 }
4595 }
4597 GtkWidget*
4598 sp_text_toolbox_new (SPDesktop *desktop)
4599 {
4600 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
4602 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4603 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4605 GtkTooltips *tt = gtk_tooltips_new();
4606 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4608 ////////////Family
4609 //Window
4610 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4611 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4613 //Entry
4614 GtkWidget *entry = gtk_entry_new ();
4615 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4616 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4617 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4618 gtk_entry_completion_set_text_column (completion, 0);
4619 gtk_entry_completion_set_minimum_key_length (completion, 1);
4620 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4621 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4622 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4623 aux_toolbox_space (tbl, 1);
4624 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
4625 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
4627 //Button
4628 GtkWidget *button = gtk_button_new ();
4629 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
4630 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
4632 //Popdown
4633 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
4634 GtkWidget *treeview = gtk_tree_view_new ();
4636 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4637 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
4638 gtk_tree_view_column_pack_start (column, cell, FALSE);
4639 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
4640 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
4641 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4643 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
4644 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
4645 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
4647 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
4649 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
4650 gtk_container_add (GTK_CONTAINER (sw), treeview);
4652 gtk_container_add (GTK_CONTAINER (window), sw);
4653 gtk_widget_set_size_request (window, 300, 450);
4655 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
4656 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
4657 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
4659 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
4661 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
4662 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
4664 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
4665 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
4667 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
4668 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
4669 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
4670 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
4671 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
4673 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
4674 aux_toolbox_space (tbl, 1);
4675 GtkWidget *box = gtk_event_box_new ();
4676 gtk_container_add (GTK_CONTAINER (box), image);
4677 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
4678 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
4679 GtkTooltips *tooltips = gtk_tooltips_new ();
4680 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
4681 gtk_widget_hide (GTK_WIDGET (box));
4682 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
4684 ////////////Size
4685 const char *sizes[] = {
4686 "4", "6", "8", "9", "10", "11", "12", "13", "14",
4687 "16", "18", "20", "22", "24", "28",
4688 "32", "36", "40", "48", "56", "64", "72", "144"
4689 };
4691 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
4692 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
4693 gtk_widget_set_size_request (cbox, 80, -1);
4694 aux_toolbox_space (tbl, 1);
4695 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
4696 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
4697 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
4698 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
4700 //spacer
4701 aux_toolbox_space (tbl, 4);
4702 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4704 ////////////Text anchor
4705 GtkWidget *group = gtk_radio_button_new (NULL);
4706 GtkWidget *row = gtk_hbox_new (FALSE, 4);
4707 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
4709 // left
4710 GtkWidget *rbutton = group;
4711 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4712 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4713 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4715 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4716 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
4717 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
4718 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
4720 // center
4721 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4722 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4723 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
4724 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4726 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4727 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
4728 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
4729 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
4731 // right
4732 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4733 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4734 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4735 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4737 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4738 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
4739 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
4740 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
4742 // fill
4743 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4744 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4745 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
4746 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4748 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4749 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
4750 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
4751 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
4753 aux_toolbox_space (tbl, 1);
4754 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4756 //spacer
4757 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4759 ////////////Text style
4760 row = gtk_hbox_new (FALSE, 4);
4762 // bold
4763 rbutton = gtk_toggle_button_new ();
4764 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4765 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
4766 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4767 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
4769 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4770 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
4771 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
4773 // italic
4774 rbutton = gtk_toggle_button_new ();
4775 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4776 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
4777 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4778 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
4780 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4781 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
4782 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
4784 aux_toolbox_space (tbl, 1);
4785 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4787 //spacer
4788 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4790 ////////////Text orientation
4791 group = gtk_radio_button_new (NULL);
4792 row = gtk_hbox_new (FALSE, 4);
4793 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4795 // horizontal
4796 rbutton = group;
4797 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4798 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4799 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4800 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4802 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4803 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4804 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4806 // vertical
4807 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4808 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4809 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4810 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4811 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4813 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4814 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4815 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4816 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4819 //watch selection
4820 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4822 sigc::connection *c_selection_changed =
4823 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4824 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4825 pool->add_connection ("selection-changed", c_selection_changed);
4827 sigc::connection *c_selection_modified =
4828 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4829 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4830 pool->add_connection ("selection-modified", c_selection_modified);
4832 sigc::connection *c_subselection_changed =
4833 new sigc::connection (desktop->connectToolSubselectionChanged
4834 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4835 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4837 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4840 gtk_widget_show_all (tbl);
4841 return tbl;
4843 } // end of sp_text_toolbox_new()
4845 }//<unnamed> namespace
4848 //#########################
4849 //## Connector ##
4850 //#########################
4852 static void sp_connector_path_set_avoid(void)
4853 {
4854 cc_selection_set_avoid(true);
4855 }
4858 static void sp_connector_path_set_ignore(void)
4859 {
4860 cc_selection_set_avoid(false);
4861 }
4865 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4866 {
4867 // quit if run by the _changed callbacks
4868 if (g_object_get_data( tbl, "freeze" )) {
4869 return;
4870 }
4872 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4873 SPDocument *doc = sp_desktop_document(desktop);
4875 if (!sp_document_get_undo_sensitive(doc))
4876 {
4877 return;
4878 }
4880 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4882 if ( repr->attribute("inkscape:connector-spacing") ) {
4883 gdouble priorValue = gtk_adjustment_get_value(adj);
4884 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4885 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4886 return;
4887 }
4888 } else if ( adj->value == defaultConnSpacing ) {
4889 return;
4890 }
4892 // in turn, prevent callbacks from responding
4893 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4895 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4896 SP_OBJECT(desktop->namedview)->updateRepr();
4898 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4899 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4900 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4901 NR::Matrix m = NR::identity();
4902 avoid_item_move(&m, item);
4903 }
4905 if (items) {
4906 g_slist_free(items);
4907 }
4909 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4910 _("Change connector spacing"));
4912 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4914 spinbutton_defocus(GTK_OBJECT(tbl));
4915 }
4917 static void sp_connector_graph_layout(void)
4918 {
4919 if (!SP_ACTIVE_DESKTOP) return;
4921 // hack for clones, see comment in align-and-distribute.cpp
4922 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4923 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4925 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4927 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4929 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4930 }
4932 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4933 {
4934 if ( gtk_toggle_action_get_active( act ) ) {
4935 prefs_set_string_attribute("tools.connector", "directedlayout",
4936 "true");
4937 } else {
4938 prefs_set_string_attribute("tools.connector", "directedlayout",
4939 "false");
4940 }
4941 }
4943 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4944 {
4945 if ( gtk_toggle_action_get_active( act ) ) {
4946 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4947 "true");
4948 } else {
4949 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4950 "false");
4951 }
4952 }
4955 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4956 {
4957 prefs_set_double_attribute("tools.connector", "length", adj->value);
4958 spinbutton_defocus(GTK_OBJECT(tbl));
4959 }
4961 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4962 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
4963 bool /*is_interactive*/, gpointer data)
4964 {
4965 GtkWidget *tbl = GTK_WIDGET(data);
4967 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4968 return;
4969 }
4970 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4971 return;
4972 }
4974 GtkAdjustment *adj = (GtkAdjustment*)
4975 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4976 gdouble spacing = defaultConnSpacing;
4977 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4979 gtk_adjustment_set_value(adj, spacing);
4980 }
4983 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4984 NULL, /* child_added */
4985 NULL, /* child_removed */
4986 connector_tb_event_attr_changed,
4987 NULL, /* content_changed */
4988 NULL /* order_changed */
4989 };
4992 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
4993 {
4994 {
4995 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
4996 _("Avoid"),
4997 _("Make connectors avoid selected objects"),
4998 "connector_avoid",
4999 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5000 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
5001 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5002 }
5004 {
5005 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
5006 _("Ignore"),
5007 _("Make connectors ignore selected objects"),
5008 "connector_ignore",
5009 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5010 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
5011 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5012 }
5014 EgeAdjustmentAction* eact = 0;
5016 // Spacing spinbox
5017 eact = create_adjustment_action( "ConnectorSpacingAction",
5018 _("Connector Spacing"), _("Spacing:"),
5019 _("The amount of space left around objects by auto-routing connectors"),
5020 "tools.connector", "spacing", defaultConnSpacing,
5021 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
5022 0, 100, 1.0, 10.0,
5023 0, 0, 0,
5024 connector_spacing_changed, 1, 0 );
5025 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5027 // Graph (connector network) layout
5028 {
5029 InkAction* inky = ink_action_new( "ConnectorGraphAction",
5030 _("Graph"),
5031 _("Nicely arrange selected connector network"),
5032 "graph_layout",
5033 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5034 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
5035 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5036 }
5038 // Default connector length spinbox
5039 eact = create_adjustment_action( "ConnectorLengthAction",
5040 _("Connector Length"), _("Length:"),
5041 _("Ideal length for connectors when layout is applied"),
5042 "tools.connector", "length", 100,
5043 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
5044 10, 1000, 10.0, 100.0,
5045 0, 0, 0,
5046 connector_length_changed, 1, 0 );
5047 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5050 // Directed edges toggle button
5051 {
5052 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
5053 _("Downwards"),
5054 _("Make connectors with end-markers (arrows) point downwards"),
5055 "directed_graph",
5056 Inkscape::ICON_SIZE_DECORATION );
5057 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5059 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
5060 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5061 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5063 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
5064 }
5066 // Avoid overlaps toggle button
5067 {
5068 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
5069 _("Remove overlaps"),
5070 _("Do not allow overlapping shapes"),
5071 "remove_overlaps",
5072 Inkscape::ICON_SIZE_DECORATION );
5073 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5075 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
5076 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5077 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5079 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
5080 }
5082 // Code to watch for changes to the connector-spacing attribute in
5083 // the XML.
5084 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5085 g_assert(repr != NULL);
5087 purge_repr_listener( holder, holder );
5089 if (repr) {
5090 g_object_set_data( holder, "repr", repr );
5091 Inkscape::GC::anchor(repr);
5092 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
5093 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
5094 }
5095 } // end of sp_connector_toolbox_prep()
5098 //#########################
5099 //## Paintbucket ##
5100 //#########################
5102 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
5103 {
5104 gint channels = ege_select_one_action_get_active( act );
5105 flood_channels_set_channels( channels );
5106 }
5108 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
5109 {
5110 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
5111 }
5113 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
5114 {
5115 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
5116 }
5118 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
5119 {
5120 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
5121 SPUnit const *unit = tracker->getActiveUnit();
5123 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
5125 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
5126 }
5128 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
5129 {
5130 // FIXME: make defaults settable via Inkscape Options
5131 struct KeyValue {
5132 char const *key;
5133 double value;
5134 } const key_values[] = {
5135 {"threshold", 15},
5136 {"offset", 0.0}
5137 };
5139 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
5140 KeyValue const &kv = key_values[i];
5141 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
5142 if ( adj ) {
5143 gtk_adjustment_set_value(adj, kv.value);
5144 }
5145 }
5147 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
5148 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
5149 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
5150 ege_select_one_action_set_active( autogap_action, 0 );
5151 }
5153 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5154 {
5155 EgeAdjustmentAction* eact = 0;
5157 {
5158 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5160 GList* items = 0;
5161 gint count = 0;
5162 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
5163 {
5164 GtkTreeIter iter;
5165 gtk_list_store_append( model, &iter );
5166 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5167 count++;
5168 }
5169 g_list_free( items );
5170 items = 0;
5171 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
5172 g_object_set( act1, "short_label", _("Fill by:"), NULL );
5173 ege_select_one_action_set_appearance( act1, "compact" );
5174 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
5175 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
5176 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
5177 g_object_set_data( holder, "channels_action", act1 );
5178 }
5180 // Spacing spinbox
5181 {
5182 eact = create_adjustment_action(
5183 "ThresholdAction",
5184 _("Fill Threshold"), _("Threshold:"),
5185 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
5186 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
5187 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
5188 0, 0, 0,
5189 paintbucket_threshold_changed, 1, 0 );
5191 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5192 }
5194 // Create the units menu.
5195 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
5196 tracker->setActiveUnit(sp_unit_get_by_abbreviation(prefs_get_string_attribute("tools.paintbucket", "offsetunits")));
5197 g_object_set_data( holder, "tracker", tracker );
5198 {
5199 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
5200 gtk_action_group_add_action( mainActions, act );
5201 }
5203 // Offset spinbox
5204 {
5205 eact = create_adjustment_action(
5206 "OffsetAction",
5207 _("Grow/shrink by"), _("Grow/shrink by:"),
5208 _("The amount to grow (positive) or shrink (negative) the created fill path"),
5209 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
5210 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
5211 0, 0, 0,
5212 paintbucket_offset_changed, 1, 2);
5213 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
5215 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5216 }
5218 /* Auto Gap */
5219 {
5220 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5222 GList* items = 0;
5223 gint count = 0;
5224 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
5225 {
5226 GtkTreeIter iter;
5227 gtk_list_store_append( model, &iter );
5228 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5229 count++;
5230 }
5231 g_list_free( items );
5232 items = 0;
5233 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
5234 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
5235 ege_select_one_action_set_appearance( act2, "compact" );
5236 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
5237 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
5238 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
5239 g_object_set_data( holder, "autogap_action", act2 );
5240 }
5242 /* Reset */
5243 {
5244 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
5245 _("Defaults"),
5246 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
5247 GTK_STOCK_CLEAR );
5248 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
5249 gtk_action_group_add_action( mainActions, act );
5250 gtk_action_set_sensitive( act, TRUE );
5251 }
5253 }
5255 /*
5256 Local Variables:
5257 mode:c++
5258 c-file-style:"stroustrup"
5259 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
5260 indent-tabs-mode:nil
5261 fill-column:99
5262 End:
5263 */
5264 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :