b0a6a7e91c0d89394968759b9933db7a3f149c1d
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 #include "svg/css-ostringstream.h"
100 using Inkscape::UnitTracker;
102 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
103 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
105 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
118 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
121 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
124 static struct {
125 gchar const *type_name;
126 gchar const *data_name;
127 sp_verb_t verb;
128 sp_verb_t doubleclick_verb;
129 } const tools[] = {
130 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
131 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
132 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
133 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
134 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
135 { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
136 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
137 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
138 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
139 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
140 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
141 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
142 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
143 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
144 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
145 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
146 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
147 { NULL, NULL, 0, 0 }
148 };
150 static struct {
151 gchar const *type_name;
152 gchar const *data_name;
153 GtkWidget *(*create_func)(SPDesktop *desktop);
154 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
155 gchar const *ui_name;
156 gint swatch_verb_id;
157 gchar const *swatch_tool;
158 gchar const *swatch_tip;
159 } const aux_toolboxes[] = {
160 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
161 SP_VERB_INVALID, 0, 0},
162 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
163 SP_VERB_INVALID, 0, 0},
164 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
165 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", _("Color/opacity used for color tweaking")},
166 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
167 SP_VERB_INVALID, 0, 0},
168 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
169 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
170 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
171 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
172 { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar",
173 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
174 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
175 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
176 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
177 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
178 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
179 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
180 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
181 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
182 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
183 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
184 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
185 SP_VERB_INVALID, 0, 0},
186 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
187 SP_VERB_INVALID, 0, 0},
188 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
189 SP_VERB_INVALID, 0, 0},
190 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
191 SP_VERB_INVALID, 0, 0},
192 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
193 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
194 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
195 };
198 static gchar const * ui_descr =
199 "<ui>"
200 " <toolbar name='SelectToolbar'>"
201 " <toolitem action='EditSelectAll' />"
202 " <toolitem action='EditSelectAllInAllLayers' />"
203 " <toolitem action='EditDeselect' />"
204 " <separator />"
205 " <toolitem action='ObjectRotate90CCW' />"
206 " <toolitem action='ObjectRotate90' />"
207 " <toolitem action='ObjectFlipHorizontally' />"
208 " <toolitem action='ObjectFlipVertically' />"
209 " <separator />"
210 " <toolitem action='SelectionToBack' />"
211 " <toolitem action='SelectionLower' />"
212 " <toolitem action='SelectionRaise' />"
213 " <toolitem action='SelectionToFront' />"
214 " <separator />"
215 " <toolitem action='XAction' />"
216 " <toolitem action='YAction' />"
217 " <toolitem action='WidthAction' />"
218 " <toolitem action='LockAction' />"
219 " <toolitem action='HeightAction' />"
220 " <toolitem action='UnitsAction' />"
221 " <separator />"
222 " <toolitem action='transform_affect_label' />"
223 " <toolitem action='transform_stroke' />"
224 " <toolitem action='transform_corners' />"
225 " <toolitem action='transform_gradient' />"
226 " <toolitem action='transform_pattern' />"
227 " </toolbar>"
229 " <toolbar name='NodeToolbar'>"
230 " <toolitem action='NodeInsertAction' />"
231 " <toolitem action='NodeDeleteAction' />"
232 " <separator />"
233 " <toolitem action='NodeJoinAction' />"
234 " <toolitem action='NodeJoinSegmentAction' />"
235 " <toolitem action='NodeDeleteSegmentAction' />"
236 " <toolitem action='NodeBreakAction' />"
237 " <separator />"
238 " <toolitem action='NodeCuspAction' />"
239 " <toolitem action='NodeSmoothAction' />"
240 " <toolitem action='NodeSymmetricAction' />"
241 " <separator />"
242 " <toolitem action='NodeLineAction' />"
243 " <toolitem action='NodeCurveAction' />"
244 " <separator />"
245 " <toolitem action='ObjectToPath' />"
246 " <toolitem action='StrokeToPath' />"
247 " <separator />"
248 " <toolitem action='NodesShowHandlesAction' />"
249 " <separator />"
250 " <toolitem action='EditNextLPEParameterAction' />"
251 " <separator />"
252 " <toolitem action='NodeXAction' />"
253 " <toolitem action='NodeYAction' />"
254 " <toolitem action='NodeUnitsAction' />"
255 " </toolbar>"
257 " <toolbar name='TweakToolbar'>"
258 " <toolitem action='TweakWidthAction' />"
259 " <separator />"
260 " <toolitem action='TweakForceAction' />"
261 " <toolitem action='TweakPressureAction' />"
262 " <separator />"
263 " <toolitem action='TweakModeAction' />"
264 " <separator />"
265 " <toolitem action='TweakFidelityAction' />"
266 " <separator />"
267 " <toolitem action='TweakChannelsLabel' />"
268 " <toolitem action='TweakDoH' />"
269 " <toolitem action='TweakDoS' />"
270 " <toolitem action='TweakDoL' />"
271 " <toolitem action='TweakDoO' />"
272 " </toolbar>"
274 " <toolbar name='ZoomToolbar'>"
275 " <toolitem action='ZoomIn' />"
276 " <toolitem action='ZoomOut' />"
277 " <separator />"
278 " <toolitem action='Zoom1:0' />"
279 " <toolitem action='Zoom1:2' />"
280 " <toolitem action='Zoom2:1' />"
281 " <separator />"
282 " <toolitem action='ZoomSelection' />"
283 " <toolitem action='ZoomDrawing' />"
284 " <toolitem action='ZoomPage' />"
285 " <toolitem action='ZoomPageWidth' />"
286 " <separator />"
287 " <toolitem action='ZoomPrev' />"
288 " <toolitem action='ZoomNext' />"
289 " </toolbar>"
291 " <toolbar name='StarToolbar'>"
292 " <separator />"
293 " <toolitem action='StarStateAction' />"
294 " <separator />"
295 " <toolitem action='FlatAction' />"
296 " <separator />"
297 " <toolitem action='MagnitudeAction' />"
298 " <toolitem action='SpokeAction' />"
299 " <toolitem action='RoundednessAction' />"
300 " <toolitem action='RandomizationAction' />"
301 " <separator />"
302 " <toolitem action='StarResetAction' />"
303 " </toolbar>"
305 " <toolbar name='RectToolbar'>"
306 " <toolitem action='RectStateAction' />"
307 " <toolitem action='RectWidthAction' />"
308 " <toolitem action='RectHeightAction' />"
309 " <toolitem action='RadiusXAction' />"
310 " <toolitem action='RadiusYAction' />"
311 " <toolitem action='RectUnitsAction' />"
312 " <separator />"
313 " <toolitem action='RectResetAction' />"
314 " </toolbar>"
316 " <toolbar name='3DBoxToolbar'>"
317 " <toolitem action='3DBoxAngleXAction' />"
318 " <toolitem action='3DBoxVPXStateAction' />"
319 " <separator />"
320 " <toolitem action='3DBoxAngleYAction' />"
321 " <toolitem action='3DBoxVPYStateAction' />"
322 " <separator />"
323 " <toolitem action='3DBoxAngleZAction' />"
324 " <toolitem action='3DBoxVPZStateAction' />"
325 " </toolbar>"
327 " <toolbar name='SpiralToolbar'>"
328 " <toolitem action='SpiralStateAction' />"
329 " <toolitem action='SpiralRevolutionAction' />"
330 " <toolitem action='SpiralExpansionAction' />"
331 " <toolitem action='SpiralT0Action' />"
332 " <separator />"
333 " <toolitem action='SpiralResetAction' />"
334 " </toolbar>"
336 " <toolbar name='PenToolbar'>"
337 " </toolbar>"
339 " <toolbar name='PencilToolbar'>"
340 " </toolbar>"
342 " <toolbar name='CalligraphyToolbar'>"
343 " <separator />"
344 " <toolitem action='CalligraphyWidthAction' />"
345 " <toolitem action='PressureAction' />"
346 " <toolitem action='TraceAction' />"
347 " <toolitem action='ThinningAction' />"
348 " <separator />"
349 " <toolitem action='AngleAction' />"
350 " <toolitem action='TiltAction' />"
351 " <toolitem action='FixationAction' />"
352 " <separator />"
353 " <toolitem action='CapRoundingAction' />"
354 " <separator />"
355 " <toolitem action='TremorAction' />"
356 " <toolitem action='WiggleAction' />"
357 " <toolitem action='MassAction' />"
358 " <separator />"
359 " <toolitem action='CalligraphyResetAction' />"
360 " </toolbar>"
362 " <toolbar name='ArcToolbar'>"
363 " <toolitem action='ArcStateAction' />"
364 " <separator />"
365 " <toolitem action='ArcStartAction' />"
366 " <toolitem action='ArcEndAction' />"
367 " <separator />"
368 " <toolitem action='ArcOpenAction' />"
369 " <separator />"
370 " <toolitem action='ArcResetAction' />"
371 " <separator />"
372 " </toolbar>"
374 " <toolbar name='PaintbucketToolbar'>"
375 " <toolitem action='ChannelsAction' />"
376 " <separator />"
377 " <toolitem action='ThresholdAction' />"
378 " <separator />"
379 " <toolitem action='OffsetAction' />"
380 " <toolitem action='PaintbucketUnitsAction' />"
381 " <separator />"
382 " <toolitem action='AutoGapAction' />"
383 " <separator />"
384 " <toolitem action='PaintbucketResetAction' />"
385 " </toolbar>"
387 " <toolbar name='DropperToolbar'>"
388 " <toolitem action='DropperPickAlphaAction' />"
389 " <toolitem action='DropperSetAlphaAction' />"
390 " </toolbar>"
392 " <toolbar name='ConnectorToolbar'>"
393 " <toolitem action='ConnectorAvoidAction' />"
394 " <toolitem action='ConnectorIgnoreAction' />"
395 " <toolitem action='ConnectorSpacingAction' />"
396 " <toolitem action='ConnectorGraphAction' />"
397 " <toolitem action='ConnectorLengthAction' />"
398 " <toolitem action='ConnectorDirectedAction' />"
399 " <toolitem action='ConnectorOverlapAction' />"
400 " </toolbar>"
402 "</ui>"
403 ;
405 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
407 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
409 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
410 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
412 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
413 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
415 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
416 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
418 /* Global text entry widgets necessary for update */
419 /* GtkWidget *dropper_rgb_entry,
420 *dropper_opacity_entry ; */
421 // should be made a private member once this is converted to class
423 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
424 connection->disconnect();
425 delete connection;
426 }
428 static void purge_repr_listener( GObject* obj, GObject* tbl )
429 {
430 (void)obj;
431 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
432 if (oldrepr) { // remove old listener
433 sp_repr_remove_listener_by_data(oldrepr, tbl);
434 Inkscape::GC::release(oldrepr);
435 oldrepr = 0;
436 g_object_set_data( tbl, "repr", NULL );
437 }
438 }
440 GtkWidget *
441 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
442 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
443 Inkscape::UI::View::View *view, GtkTooltips *tt)
444 {
445 SPAction *action = verb->get_action(view);
446 if (!action) return NULL;
448 SPAction *doubleclick_action;
449 if (doubleclick_verb)
450 doubleclick_action = doubleclick_verb->get_action(view);
451 else
452 doubleclick_action = NULL;
454 /* fixme: Handle sensitive/unsensitive */
455 /* fixme: Implement sp_button_new_from_action */
456 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
457 gtk_widget_show(b);
458 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
460 return b;
461 }
463 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
464 Inkscape::UI::View::View *view, GtkTooltips *tt)
465 {
466 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
467 }
469 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
470 Inkscape::UI::View::View *view, GtkTooltips *tt)
471 {
472 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
473 }
476 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
477 {
478 SPAction* targetAction = SP_ACTION(user_data);
479 if ( targetAction ) {
480 sp_action_perform( targetAction, NULL );
481 }
482 }
484 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
485 {
486 if ( data ) {
487 GtkAction* act = GTK_ACTION(data);
488 gtk_action_set_sensitive( act, sensitive );
489 }
490 }
492 static SPActionEventVector action_event_vector = {
493 {NULL},
494 NULL,
495 NULL,
496 sp_action_action_set_sensitive,
497 NULL,
498 NULL
499 };
501 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
502 {
503 GtkAction* act = 0;
505 SPAction* targetAction = verb->get_action(view);
506 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
507 act = GTK_ACTION(inky);
508 gtk_action_set_sensitive( act, targetAction->sensitive );
510 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
512 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
513 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
515 return act;
516 }
518 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
519 {
520 Inkscape::UI::View::View *view = desktop;
521 gint verbsToUse[] = {
522 // disabled until we have icons for them:
523 //find
524 //SP_VERB_EDIT_TILE,
525 //SP_VERB_EDIT_UNTILE,
526 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
527 SP_VERB_DIALOG_DISPLAY,
528 SP_VERB_DIALOG_FILL_STROKE,
529 SP_VERB_DIALOG_NAMEDVIEW,
530 SP_VERB_DIALOG_TEXT,
531 SP_VERB_DIALOG_XML_EDITOR,
532 SP_VERB_EDIT_CLONE,
533 SP_VERB_EDIT_COPY,
534 SP_VERB_EDIT_CUT,
535 SP_VERB_EDIT_DUPLICATE,
536 SP_VERB_EDIT_PASTE,
537 SP_VERB_EDIT_REDO,
538 SP_VERB_EDIT_UNDO,
539 SP_VERB_EDIT_UNLINK_CLONE,
540 SP_VERB_FILE_EXPORT,
541 SP_VERB_FILE_IMPORT,
542 SP_VERB_FILE_NEW,
543 SP_VERB_FILE_OPEN,
544 SP_VERB_FILE_PRINT,
545 SP_VERB_FILE_SAVE,
546 SP_VERB_OBJECT_TO_CURVE,
547 SP_VERB_SELECTION_GROUP,
548 SP_VERB_SELECTION_OUTLINE,
549 SP_VERB_SELECTION_UNGROUP,
550 SP_VERB_ZOOM_1_1,
551 SP_VERB_ZOOM_1_2,
552 SP_VERB_ZOOM_2_1,
553 SP_VERB_ZOOM_DRAWING,
554 SP_VERB_ZOOM_IN,
555 SP_VERB_ZOOM_NEXT,
556 SP_VERB_ZOOM_OUT,
557 SP_VERB_ZOOM_PAGE,
558 SP_VERB_ZOOM_PAGE_WIDTH,
559 SP_VERB_ZOOM_PREV,
560 SP_VERB_ZOOM_SELECTION,
561 };
563 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
564 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
566 static std::map<SPDesktop*, GtkActionGroup*> groups;
567 GtkActionGroup* mainActions = 0;
568 if ( groups.find(desktop) != groups.end() ) {
569 mainActions = groups[desktop];
570 }
572 if ( !mainActions ) {
573 mainActions = gtk_action_group_new("main");
574 groups[desktop] = mainActions;
575 }
577 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
578 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
579 if ( verb ) {
580 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
581 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
582 gtk_action_group_add_action( mainActions, act );
583 }
584 }
585 }
587 return mainActions;
588 }
591 GtkWidget *
592 sp_tool_toolbox_new()
593 {
594 GtkTooltips *tt = gtk_tooltips_new();
595 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
597 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
598 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
600 gtk_widget_set_sensitive(tb, FALSE);
602 GtkWidget *hb = gtk_handle_box_new();
603 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
604 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
605 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
607 gtk_container_add(GTK_CONTAINER(hb), tb);
608 gtk_widget_show(GTK_WIDGET(tb));
610 sigc::connection* conn = new sigc::connection;
611 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
613 return hb;
614 }
616 static void
617 aux_toolbox_attached(GtkHandleBox */*toolbox*/, GtkWidget *child)
618 {
619 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
620 gtk_widget_queue_resize(child);
621 }
623 static void
624 aux_toolbox_detached(GtkHandleBox */*toolbox*/, GtkWidget *child)
625 {
626 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
627 gtk_widget_queue_resize(child);
628 }
630 GtkWidget *
631 sp_aux_toolbox_new()
632 {
633 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
635 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
637 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
639 gtk_widget_set_sensitive(tb, FALSE);
641 GtkWidget *hb = gtk_handle_box_new();
642 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
643 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
644 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
646 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
647 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
649 gtk_container_add(GTK_CONTAINER(hb), tb);
650 gtk_widget_show(GTK_WIDGET(tb));
652 sigc::connection* conn = new sigc::connection;
653 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
655 return hb;
656 }
658 //####################################
659 //# Commands Bar
660 //####################################
662 GtkWidget *
663 sp_commands_toolbox_new()
664 {
665 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
667 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
669 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
670 gtk_widget_set_sensitive(tb, FALSE);
672 GtkWidget *hb = gtk_handle_box_new();
673 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
674 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
675 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
677 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
678 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
680 gtk_container_add(GTK_CONTAINER(hb), tb);
681 gtk_widget_show(GTK_WIDGET(tb));
683 sigc::connection* conn = new sigc::connection;
684 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
686 return hb;
687 }
689 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
690 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
691 gchar const *path, gchar const *data, gdouble def,
692 GtkWidget *focusTarget,
693 GtkWidget *us,
694 GObject *dataKludge,
695 gboolean altx, gchar const *altx_mark,
696 gdouble lower, gdouble upper, gdouble step, gdouble page,
697 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
698 void (*callback)(GtkAdjustment *, GObject *),
699 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
700 {
701 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
702 lower, upper, step, page, page ) );
703 if (us) {
704 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
705 }
707 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
709 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
710 if ( shortLabel ) {
711 g_object_set( act, "short_label", shortLabel, NULL );
712 }
714 if ( (descrCount > 0) && descrLabels && descrValues ) {
715 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
716 }
718 if ( focusTarget ) {
719 ege_adjustment_action_set_focuswidget( act, focusTarget );
720 }
722 if ( altx && altx_mark ) {
723 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
724 }
726 if ( dataKludge ) {
727 g_object_set_data( dataKludge, data, adj );
728 }
730 // Using a cast just to make sure we pass in the right kind of function pointer
731 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
733 return act;
734 }
737 //####################################
738 //# node editing callbacks
739 //####################################
741 /**
742 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
743 */
744 static ShapeEditor *get_current_shape_editor()
745 {
746 if (!SP_ACTIVE_DESKTOP) {
747 return NULL;
748 }
750 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
752 if (!SP_IS_NODE_CONTEXT(event_context)) {
753 return NULL;
754 }
756 return SP_NODE_CONTEXT(event_context)->shape_editor;
757 }
760 void
761 sp_node_path_edit_add(void)
762 {
763 ShapeEditor *shape_editor = get_current_shape_editor();
764 if (shape_editor) shape_editor->add_node();
765 }
767 void
768 sp_node_path_edit_delete(void)
769 {
770 ShapeEditor *shape_editor = get_current_shape_editor();
771 if (shape_editor) shape_editor->delete_nodes();
772 }
774 void
775 sp_node_path_edit_delete_segment(void)
776 {
777 ShapeEditor *shape_editor = get_current_shape_editor();
778 if (shape_editor) shape_editor->delete_segment();
779 }
781 void
782 sp_node_path_edit_break(void)
783 {
784 ShapeEditor *shape_editor = get_current_shape_editor();
785 if (shape_editor) shape_editor->break_at_nodes();
786 }
788 void
789 sp_node_path_edit_join(void)
790 {
791 ShapeEditor *shape_editor = get_current_shape_editor();
792 if (shape_editor) shape_editor->join_nodes();
793 }
795 void
796 sp_node_path_edit_join_segment(void)
797 {
798 ShapeEditor *shape_editor = get_current_shape_editor();
799 if (shape_editor) shape_editor->join_segments();
800 }
802 void
803 sp_node_path_edit_toline(void)
804 {
805 ShapeEditor *shape_editor = get_current_shape_editor();
806 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
807 }
809 void
810 sp_node_path_edit_tocurve(void)
811 {
812 ShapeEditor *shape_editor = get_current_shape_editor();
813 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
814 }
816 void
817 sp_node_path_edit_cusp(void)
818 {
819 ShapeEditor *shape_editor = get_current_shape_editor();
820 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
821 }
823 void
824 sp_node_path_edit_smooth(void)
825 {
826 ShapeEditor *shape_editor = get_current_shape_editor();
827 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
828 }
830 void
831 sp_node_path_edit_symmetrical(void)
832 {
833 ShapeEditor *shape_editor = get_current_shape_editor();
834 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
835 }
837 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
838 bool show = gtk_toggle_action_get_active( act );
839 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
840 ShapeEditor *shape_editor = get_current_shape_editor();
841 if (shape_editor) shape_editor->show_handles(show);
842 }
844 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
845 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
846 }
848 /* is called when the node selection is modified */
849 static void
850 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
851 {
852 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
853 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
854 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
855 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
857 // quit if run by the attr_changed listener
858 if (g_object_get_data( tbl, "freeze" )) {
859 return;
860 }
862 // in turn, prevent listener from responding
863 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
865 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
866 SPUnit const *unit = tracker->getActiveUnit();
868 ShapeEditor *shape_editor = get_current_shape_editor();
869 if (shape_editor && shape_editor->has_nodepath()) {
870 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
871 int n_selected = 0;
872 if (nodepath) {
873 n_selected = nodepath->numSelected();
874 }
876 if (n_selected == 0) {
877 gtk_action_set_sensitive(xact, FALSE);
878 gtk_action_set_sensitive(yact, FALSE);
879 } else {
880 gtk_action_set_sensitive(xact, TRUE);
881 gtk_action_set_sensitive(yact, TRUE);
882 NR::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
883 NR::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
885 if (n_selected == 1) {
886 NR::Point sel_node = nodepath->singleSelectedCoords();
887 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
888 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[NR::X], *unit));
889 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[NR::Y], *unit));
890 }
891 } else {
892 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
893 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
894 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
895 /* Note: Currently x and y will always have a value, even if the coordinates of the
896 selected nodes don't coincide (in this case we use the coordinates of the center
897 of the bounding box). So the entries are never set to zero. */
898 // FIXME: Maybe we should clear the entry if several nodes are selected
899 // instead of providing a kind of average value
900 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
901 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
902 }
903 }
904 }
905 } else {
906 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
907 gtk_action_set_sensitive(xact, FALSE);
908 gtk_action_set_sensitive(yact, FALSE);
909 }
911 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
912 }
914 static void
915 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
916 {
917 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
919 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
920 SPUnit const *unit = tracker->getActiveUnit();
922 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
923 prefs_set_double_attribute("tools.nodes", value_name, sp_units_get_pixels(adj->value, *unit));
924 }
926 // quit if run by the attr_changed listener
927 if (g_object_get_data( tbl, "freeze" )) {
928 return;
929 }
931 // in turn, prevent listener from responding
932 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
934 ShapeEditor *shape_editor = get_current_shape_editor();
935 if (shape_editor && shape_editor->has_nodepath()) {
936 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
937 if (!strcmp(value_name, "x")) {
938 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::X);
939 }
940 if (!strcmp(value_name, "y")) {
941 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::Y);
942 }
943 }
945 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
946 }
948 static void
949 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
950 {
951 sp_node_path_value_changed(adj, tbl, "x");
952 }
954 static void
955 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
956 {
957 sp_node_path_value_changed(adj, tbl, "y");
958 }
960 //################################
961 //## Node Editing Toolbox ##
962 //################################
964 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
965 {
966 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
967 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
968 g_object_set_data( holder, "tracker", tracker );
970 {
971 InkAction* inky = ink_action_new( "NodeInsertAction",
972 _("Insert node"),
973 _("Insert new nodes into selected segments"),
974 "node_insert",
975 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
976 g_object_set( inky, "short_label", _("Insert"), NULL );
977 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
978 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
979 }
981 {
982 InkAction* inky = ink_action_new( "NodeDeleteAction",
983 _("Delete node"),
984 _("Delete selected nodes"),
985 "node_delete",
986 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
987 g_object_set( inky, "short_label", _("Delete"), NULL );
988 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
989 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
990 }
992 {
993 InkAction* inky = ink_action_new( "NodeJoinAction",
994 _("Join endnodes"),
995 _("Join selected endnodes"),
996 "node_join",
997 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
998 g_object_set( inky, "short_label", _("Join"), NULL );
999 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1000 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1001 }
1003 {
1004 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1005 _("Join Segment"),
1006 _("Join selected endnodes with a new segment"),
1007 "node_join_segment",
1008 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1009 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1010 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1011 }
1013 {
1014 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1015 _("Delete Segment"),
1016 _("Split path between two non-endpoint nodes"),
1017 "node_delete_segment",
1018 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1019 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1020 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1021 }
1023 {
1024 InkAction* inky = ink_action_new( "NodeBreakAction",
1025 _("Node Break"),
1026 _("Break path at selected nodes"),
1027 "node_break",
1028 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1029 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1030 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1031 }
1033 {
1034 InkAction* inky = ink_action_new( "NodeCuspAction",
1035 _("Node Cusp"),
1036 _("Make selected nodes corner"),
1037 "node_cusp",
1038 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1039 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1040 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1041 }
1043 {
1044 InkAction* inky = ink_action_new( "NodeSmoothAction",
1045 _("Node Smooth"),
1046 _("Make selected nodes smooth"),
1047 "node_smooth",
1048 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1049 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1050 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1051 }
1053 {
1054 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1055 _("Node Symmetric"),
1056 _("Make selected nodes symmetric"),
1057 "node_symmetric",
1058 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1059 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1060 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1061 }
1063 {
1064 InkAction* inky = ink_action_new( "NodeLineAction",
1065 _("Node Line"),
1066 _("Make selected segments lines"),
1067 "node_line",
1068 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1069 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1070 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1071 }
1073 {
1074 InkAction* inky = ink_action_new( "NodeCurveAction",
1075 _("Node Curve"),
1076 _("Make selected segments curves"),
1077 "node_curve",
1078 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1079 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1080 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1081 }
1083 {
1084 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1085 _("Show Handles"),
1086 _("Show the Bezier handles of selected nodes"),
1087 "nodes_show_handles",
1088 Inkscape::ICON_SIZE_DECORATION );
1089 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1090 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1091 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1092 }
1094 {
1095 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1096 _("Next Path Effect Parameter"),
1097 _("Show next Path Effect parameter for editing"),
1098 "edit_next_parameter",
1099 Inkscape::ICON_SIZE_DECORATION );
1100 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1101 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1102 }
1104 /* X coord of selected node(s) */
1105 {
1106 EgeAdjustmentAction* eact = 0;
1107 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1108 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1109 eact = create_adjustment_action( "NodeXAction",
1110 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1111 "tools.nodes", "Xcoord", 0,
1112 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1113 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1114 labels, values, G_N_ELEMENTS(labels),
1115 sp_node_path_x_value_changed );
1116 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1117 g_object_set_data( holder, "nodes_x_action", eact );
1118 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1119 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1120 }
1122 /* Y coord of selected node(s) */
1123 {
1124 EgeAdjustmentAction* eact = 0;
1125 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1126 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1127 eact = create_adjustment_action( "NodeYAction",
1128 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1129 "tools.nodes", "Ycoord", 0,
1130 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1131 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1132 labels, values, G_N_ELEMENTS(labels),
1133 sp_node_path_y_value_changed );
1134 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1135 g_object_set_data( holder, "nodes_y_action", eact );
1136 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1137 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1138 }
1140 // add the units menu
1141 {
1142 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1143 gtk_action_group_add_action( mainActions, act );
1144 }
1146 sigc::connection *connection = new sigc::connection (
1147 desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(sp_node_toolbox_coord_changed), (GObject *)holder))
1148 );
1150 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1151 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1152 } // end of sp_node_toolbox_prep()
1155 //########################
1156 //## Zoom Toolbox ##
1157 //########################
1159 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1160 {
1161 // no custom GtkAction setup needed
1162 } // end of sp_zoom_toolbox_prep()
1164 void
1165 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1166 {
1167 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")));
1168 }
1171 void
1172 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1173 {
1174 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")));
1175 }
1177 void
1178 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1179 {
1180 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")));
1181 }
1183 static void
1184 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1185 {
1186 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1187 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1189 if (old_desktop) {
1190 GList *children, *iter;
1192 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1193 for ( iter = children ; iter ; iter = iter->next ) {
1194 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1195 }
1196 g_list_free(children);
1197 }
1199 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1201 if (desktop) {
1202 gtk_widget_set_sensitive(toolbox, TRUE);
1203 setup_func(toolbox, desktop);
1204 update_func(desktop, desktop->event_context, toolbox);
1205 *conn = desktop->connectEventContextChanged
1206 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1207 } else {
1208 gtk_widget_set_sensitive(toolbox, FALSE);
1209 }
1211 } // end of toolbox_set_desktop()
1214 static void
1215 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1216 {
1217 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
1218 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
1219 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
1220 // "toolbox.tools" was not set. Fallback to older value
1221 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
1223 // Copy the setting forwards
1224 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
1225 }
1226 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1228 for (int i = 0 ; tools[i].type_name ; i++ ) {
1229 GtkWidget *button =
1230 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
1231 SP_BUTTON_TYPE_TOGGLE,
1232 Inkscape::Verb::get(tools[i].verb),
1233 Inkscape::Verb::get(tools[i].doubleclick_verb),
1234 desktop,
1235 tooltips );
1237 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1238 (gpointer)button );
1239 }
1240 }
1243 static void
1244 update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
1245 {
1246 gchar const *const tname = ( eventcontext
1247 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1248 : NULL );
1249 for (int i = 0 ; tools[i].type_name ; i++ ) {
1250 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1251 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1252 }
1253 }
1255 static void
1256 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1257 {
1258 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1259 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1260 GtkUIManager* mgr = gtk_ui_manager_new();
1261 GError* errVal = 0;
1262 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1263 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1265 std::map<std::string, GtkWidget*> dataHolders;
1267 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1268 if ( aux_toolboxes[i].prep_func ) {
1269 // converted to GtkActions and UIManager
1271 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1272 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1273 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1274 dataHolders[aux_toolboxes[i].type_name] = kludge;
1275 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1276 } else {
1278 GtkWidget *sub_toolbox = 0;
1279 if (aux_toolboxes[i].create_func == NULL)
1280 sub_toolbox = sp_empty_toolbox_new(desktop);
1281 else {
1282 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1283 }
1285 gtk_size_group_add_widget( grouper, sub_toolbox );
1287 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1288 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1290 }
1291 }
1293 // Second pass to create toolbars *after* all GtkActions are created
1294 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1295 if ( aux_toolboxes[i].prep_func ) {
1296 // converted to GtkActions and UIManager
1298 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1300 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1301 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1303 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1304 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1305 g_free( tmp );
1306 tmp = 0;
1308 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1309 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1310 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1311 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1312 }
1313 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1316 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1318 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1319 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1320 swatch->setDesktop( desktop );
1321 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1322 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1323 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1324 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 );
1325 }
1327 gtk_widget_show_all( holder );
1328 sp_set_font_size_smaller( holder );
1330 gtk_size_group_add_widget( grouper, holder );
1332 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1333 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1334 }
1335 }
1337 g_object_unref( G_OBJECT(grouper) );
1338 }
1340 static void
1341 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1342 {
1343 gchar const *tname = ( eventcontext
1344 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1345 : NULL );
1346 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1347 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1348 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1349 gtk_widget_show_all(sub_toolbox);
1350 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1351 } else {
1352 gtk_widget_hide(sub_toolbox);
1353 }
1354 }
1355 }
1357 static void
1358 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1359 {
1360 gchar const * descr =
1361 "<ui>"
1362 " <toolbar name='CommandsToolbar'>"
1363 " <toolitem action='FileNew' />"
1364 " <toolitem action='FileOpen' />"
1365 " <toolitem action='FileSave' />"
1366 " <toolitem action='FilePrint' />"
1367 " <separator />"
1368 " <toolitem action='FileImport' />"
1369 " <toolitem action='FileExport' />"
1370 " <separator />"
1371 " <toolitem action='EditUndo' />"
1372 " <toolitem action='EditRedo' />"
1373 " <separator />"
1374 " <toolitem action='EditCopy' />"
1375 " <toolitem action='EditCut' />"
1376 " <toolitem action='EditPaste' />"
1377 " <separator />"
1378 " <toolitem action='ZoomSelection' />"
1379 " <toolitem action='ZoomDrawing' />"
1380 " <toolitem action='ZoomPage' />"
1381 " <separator />"
1382 " <toolitem action='EditDuplicate' />"
1383 " <toolitem action='EditClone' />"
1384 " <toolitem action='EditUnlinkClone' />"
1385 " <separator />"
1386 " <toolitem action='SelectionGroup' />"
1387 " <toolitem action='SelectionUnGroup' />"
1388 " <separator />"
1389 " <toolitem action='DialogFillStroke' />"
1390 " <toolitem action='DialogText' />"
1391 " <toolitem action='DialogXMLEditor' />"
1392 " <toolitem action='DialogAlignDistribute' />"
1393 " <separator />"
1394 " <toolitem action='DialogPreferences' />"
1395 " <toolitem action='DialogDocumentProperties' />"
1396 " </toolbar>"
1397 "</ui>";
1398 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1401 GtkUIManager* mgr = gtk_ui_manager_new();
1402 GError* errVal = 0;
1404 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1405 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1407 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1408 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1409 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1410 }
1411 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1412 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1413 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1416 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1417 }
1419 static void
1420 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1421 {
1422 }
1424 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1425 {
1426 gtk_widget_show(toolbox_toplevel);
1427 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1429 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1430 if (!shown_toolbox) {
1431 return;
1432 }
1433 gtk_widget_show(toolbox);
1435 gtk_widget_show_all(shown_toolbox);
1436 }
1438 void
1439 aux_toolbox_space(GtkWidget *tb, gint space)
1440 {
1441 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1442 }
1444 static GtkWidget *
1445 sp_empty_toolbox_new(SPDesktop *desktop)
1446 {
1447 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1448 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1449 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1451 gtk_widget_show_all(tbl);
1452 sp_set_font_size_smaller (tbl);
1454 return tbl;
1455 }
1457 // helper UI functions
1459 GtkWidget *
1460 sp_tb_spinbutton(
1461 gchar *label, gchar const *tooltip,
1462 gchar const *path, gchar const *data, gdouble def,
1463 GtkWidget *us,
1464 GtkWidget *tbl,
1465 gboolean altx, gchar const *altx_mark,
1466 gdouble lower, gdouble upper, gdouble step, gdouble page,
1467 void (*callback)(GtkAdjustment *, GtkWidget *),
1468 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1469 {
1470 GtkTooltips *tt = gtk_tooltips_new();
1472 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1474 GtkWidget *l = gtk_label_new(label);
1475 gtk_widget_show(l);
1476 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1477 gtk_container_add(GTK_CONTAINER(hb), l);
1479 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1480 lower, upper, step, page, page);
1481 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1482 if (us)
1483 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1485 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1486 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1487 if (altx)
1488 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1489 gtk_widget_set_size_request(sb,
1490 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1491 AUX_SPINBUTTON_HEIGHT);
1492 gtk_widget_show(sb);
1493 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1494 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1495 gtk_container_add(GTK_CONTAINER(hb), sb);
1496 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1498 return hb;
1499 }
1501 #define MODE_LABEL_WIDTH 70
1503 //########################
1504 //## Star ##
1505 //########################
1507 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1508 {
1509 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1511 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1512 // do not remember prefs if this call is initiated by an undo change, because undoing object
1513 // creation sets bogus values to its attributes before it is deleted
1514 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1515 }
1517 // quit if run by the attr_changed listener
1518 if (g_object_get_data( dataKludge, "freeze" )) {
1519 return;
1520 }
1522 // in turn, prevent listener from responding
1523 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1525 bool modmade = false;
1527 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1528 GSList const *items = selection->itemList();
1529 for (; items != NULL; items = items->next) {
1530 if (SP_IS_STAR((SPItem *) items->data)) {
1531 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1532 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1533 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1534 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1535 + M_PI / (gint)adj->value));
1536 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1537 modmade = true;
1538 }
1539 }
1540 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1541 _("Star: Change number of corners"));
1543 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1544 }
1546 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1547 {
1548 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1550 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1551 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1552 }
1554 // quit if run by the attr_changed listener
1555 if (g_object_get_data( dataKludge, "freeze" )) {
1556 return;
1557 }
1559 // in turn, prevent listener from responding
1560 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1562 bool modmade = false;
1563 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1564 GSList const *items = selection->itemList();
1565 for (; items != NULL; items = items->next) {
1566 if (SP_IS_STAR((SPItem *) items->data)) {
1567 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1569 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1570 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1571 if (r2 < r1) {
1572 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1573 } else {
1574 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1575 }
1577 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1578 modmade = true;
1579 }
1580 }
1582 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1583 _("Star: Change spoke ratio"));
1585 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1586 }
1588 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1589 {
1590 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1591 bool flat = ege_select_one_action_get_active( act ) == 0;
1593 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1594 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1595 flat ? "true" : "false" );
1596 }
1598 // quit if run by the attr_changed listener
1599 if (g_object_get_data( dataKludge, "freeze" )) {
1600 return;
1601 }
1603 // in turn, prevent listener from responding
1604 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1606 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1607 GSList const *items = selection->itemList();
1608 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1609 bool modmade = false;
1611 if ( prop_action ) {
1612 gtk_action_set_sensitive( prop_action, !flat );
1613 }
1615 for (; items != NULL; items = items->next) {
1616 if (SP_IS_STAR((SPItem *) items->data)) {
1617 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1618 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1619 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1620 modmade = true;
1621 }
1622 }
1624 if (modmade) {
1625 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1626 flat ? _("Make polygon") : _("Make star"));
1627 }
1629 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1630 }
1632 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1633 {
1634 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1636 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1637 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1638 }
1640 // quit if run by the attr_changed listener
1641 if (g_object_get_data( dataKludge, "freeze" )) {
1642 return;
1643 }
1645 // in turn, prevent listener from responding
1646 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1648 bool modmade = false;
1650 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1651 GSList const *items = selection->itemList();
1652 for (; items != NULL; items = items->next) {
1653 if (SP_IS_STAR((SPItem *) items->data)) {
1654 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1655 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1656 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1657 modmade = true;
1658 }
1659 }
1660 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1661 _("Star: Change rounding"));
1663 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1664 }
1666 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1667 {
1668 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1670 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1671 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1672 }
1674 // quit if run by the attr_changed listener
1675 if (g_object_get_data( dataKludge, "freeze" )) {
1676 return;
1677 }
1679 // in turn, prevent listener from responding
1680 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1682 bool modmade = false;
1684 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1685 GSList const *items = selection->itemList();
1686 for (; items != NULL; items = items->next) {
1687 if (SP_IS_STAR((SPItem *) items->data)) {
1688 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1689 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1690 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1691 modmade = true;
1692 }
1693 }
1694 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1695 _("Star: Change randomization"));
1697 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1698 }
1701 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1702 gchar const */*old_value*/, gchar const */*new_value*/,
1703 bool /*is_interactive*/, gpointer data)
1704 {
1705 GtkWidget *tbl = GTK_WIDGET(data);
1707 // quit if run by the _changed callbacks
1708 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1709 return;
1710 }
1712 // in turn, prevent callbacks from responding
1713 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1715 GtkAdjustment *adj = 0;
1717 if (!strcmp(name, "inkscape:randomized")) {
1718 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1719 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1720 } else if (!strcmp(name, "inkscape:rounded")) {
1721 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1722 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1723 } else if (!strcmp(name, "inkscape:flatsided")) {
1724 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1725 char const *flatsides = repr->attribute("inkscape:flatsided");
1726 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1727 if ( flatsides && !strcmp(flatsides,"false") ) {
1728 ege_select_one_action_set_active( flat_action, 1 );
1729 gtk_action_set_sensitive( prop_action, TRUE );
1730 } else {
1731 ege_select_one_action_set_active( flat_action, 0 );
1732 gtk_action_set_sensitive( prop_action, FALSE );
1733 }
1734 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1735 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1736 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1737 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1738 if (r2 < r1) {
1739 gtk_adjustment_set_value(adj, r2/r1);
1740 } else {
1741 gtk_adjustment_set_value(adj, r1/r2);
1742 }
1743 } else if (!strcmp(name, "sodipodi:sides")) {
1744 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1745 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1746 }
1748 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1749 }
1752 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1753 {
1754 NULL, /* child_added */
1755 NULL, /* child_removed */
1756 star_tb_event_attr_changed,
1757 NULL, /* content_changed */
1758 NULL /* order_changed */
1759 };
1762 /**
1763 * \param selection Should not be NULL.
1764 */
1765 static void
1766 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1767 {
1768 int n_selected = 0;
1769 Inkscape::XML::Node *repr = NULL;
1771 purge_repr_listener( tbl, tbl );
1773 for (GSList const *items = selection->itemList();
1774 items != NULL;
1775 items = items->next)
1776 {
1777 if (SP_IS_STAR((SPItem *) items->data)) {
1778 n_selected++;
1779 repr = SP_OBJECT_REPR((SPItem *) items->data);
1780 }
1781 }
1783 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1785 if (n_selected == 0) {
1786 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1787 } else if (n_selected == 1) {
1788 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1790 if (repr) {
1791 g_object_set_data( tbl, "repr", repr );
1792 Inkscape::GC::anchor(repr);
1793 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1794 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1795 }
1796 } else {
1797 // FIXME: implement averaging of all parameters for multiple selected stars
1798 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1799 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1800 }
1801 }
1804 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
1805 {
1806 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1807 // callbacks to lump all the changes for all selected objects in one undo step
1809 GtkAdjustment *adj = 0;
1811 // fixme: make settable in prefs!
1812 gint mag = 5;
1813 gdouble prop = 0.5;
1814 gboolean flat = FALSE;
1815 gdouble randomized = 0;
1816 gdouble rounded = 0;
1818 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1819 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1821 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1822 gtk_action_set_sensitive( sb2, !flat );
1824 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1825 gtk_adjustment_set_value(adj, mag);
1826 gtk_adjustment_value_changed(adj);
1828 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1829 gtk_adjustment_set_value(adj, prop);
1830 gtk_adjustment_value_changed(adj);
1832 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1833 gtk_adjustment_set_value(adj, rounded);
1834 gtk_adjustment_value_changed(adj);
1836 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1837 gtk_adjustment_set_value(adj, randomized);
1838 gtk_adjustment_value_changed(adj);
1839 }
1842 void
1843 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1844 {
1845 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1846 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1847 GtkWidget *l = gtk_label_new(NULL);
1848 gtk_label_set_markup(GTK_LABEL(l), title);
1849 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1850 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1851 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1852 }
1855 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1856 {
1857 {
1858 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1859 ege_output_action_set_use_markup( act, TRUE );
1860 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1861 g_object_set_data( holder, "mode_action", act );
1862 }
1864 {
1865 EgeAdjustmentAction* eact = 0;
1866 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1867 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1869 /* Flatsided checkbox */
1870 {
1871 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1873 GtkTreeIter iter;
1874 gtk_list_store_append( model, &iter );
1875 gtk_list_store_set( model, &iter,
1876 0, _("Polygon"),
1877 1, _("Regular polygon (with one handle) instead of a star"),
1878 2, "star_flat",
1879 -1 );
1881 gtk_list_store_append( model, &iter );
1882 gtk_list_store_set( model, &iter,
1883 0, _("Star"),
1884 1, _("Star instead of a regular polygon (with one handle)"),
1885 2, "star_angled",
1886 -1 );
1888 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
1889 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1890 g_object_set_data( holder, "flat_action", act );
1892 ege_select_one_action_set_appearance( act, "full" );
1893 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1894 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1895 ege_select_one_action_set_icon_column( act, 2 );
1896 ege_select_one_action_set_tooltip_column( act, 1 );
1898 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1899 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1900 }
1902 /* Magnitude */
1903 {
1904 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
1905 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
1906 eact = create_adjustment_action( "MagnitudeAction",
1907 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
1908 "tools.shapes.star", "magnitude", 3,
1909 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1910 3, 1024, 1, 5,
1911 labels, values, G_N_ELEMENTS(labels),
1912 sp_stb_magnitude_value_changed,
1913 1.0, 0 );
1914 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1915 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1916 }
1918 /* Spoke ratio */
1919 {
1920 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
1921 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
1922 eact = create_adjustment_action( "SpokeAction",
1923 _("Spoke ratio"), _("Spoke ratio:"),
1924 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1925 // Base radius is the same for the closest handle.
1926 _("Base radius to tip radius ratio"),
1927 "tools.shapes.star", "proportion", 0.5,
1928 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1929 0.01, 1.0, 0.01, 0.1,
1930 labels, values, G_N_ELEMENTS(labels),
1931 sp_stb_proportion_value_changed );
1932 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1933 g_object_set_data( holder, "prop_action", eact );
1934 }
1936 if ( !isFlatSided ) {
1937 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1938 } else {
1939 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1940 }
1942 /* Roundedness */
1943 {
1944 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
1945 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
1946 eact = create_adjustment_action( "RoundednessAction",
1947 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1948 "tools.shapes.star", "rounded", 0.0,
1949 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1950 -10.0, 10.0, 0.01, 0.1,
1951 labels, values, G_N_ELEMENTS(labels),
1952 sp_stb_rounded_value_changed );
1953 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1954 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1955 }
1957 /* Randomization */
1958 {
1959 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
1960 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
1961 eact = create_adjustment_action( "RandomizationAction",
1962 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
1963 "tools.shapes.star", "randomized", 0.0,
1964 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1965 -10.0, 10.0, 0.001, 0.01,
1966 labels, values, G_N_ELEMENTS(labels),
1967 sp_stb_randomized_value_changed, 0.1, 3 );
1968 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1969 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1970 }
1971 }
1973 {
1974 /* Reset */
1975 {
1976 GtkAction* act = gtk_action_new( "StarResetAction",
1977 _("Defaults"),
1978 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1979 GTK_STOCK_CLEAR );
1980 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1981 gtk_action_group_add_action( mainActions, act );
1982 gtk_action_set_sensitive( act, TRUE );
1983 }
1984 }
1986 sigc::connection *connection = new sigc::connection(
1987 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1988 );
1989 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1990 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1991 }
1994 //########################
1995 //## Rect ##
1996 //########################
1998 static void sp_rtb_sensitivize( GObject *tbl )
1999 {
2000 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
2001 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
2002 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
2004 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
2005 gtk_action_set_sensitive( not_rounded, FALSE );
2006 } else {
2007 gtk_action_set_sensitive( not_rounded, TRUE );
2008 }
2009 }
2012 static void
2013 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
2014 void (*setter)(SPRect *, gdouble))
2015 {
2016 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2018 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2019 SPUnit const *unit = tracker->getActiveUnit();
2021 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2022 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
2023 }
2025 // quit if run by the attr_changed listener
2026 if (g_object_get_data( tbl, "freeze" )) {
2027 return;
2028 }
2030 // in turn, prevent listener from responding
2031 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2033 bool modmade = false;
2034 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2035 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2036 if (SP_IS_RECT(items->data)) {
2037 if (adj->value != 0) {
2038 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2039 } else {
2040 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2041 }
2042 modmade = true;
2043 }
2044 }
2046 sp_rtb_sensitivize( tbl );
2048 if (modmade) {
2049 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2050 _("Change rectangle"));
2051 }
2053 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2054 }
2056 static void
2057 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2058 {
2059 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2060 }
2062 static void
2063 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2064 {
2065 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2066 }
2068 static void
2069 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2070 {
2071 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2072 }
2074 static void
2075 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2076 {
2077 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2078 }
2082 static void
2083 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2084 {
2085 GtkAdjustment *adj = 0;
2087 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2088 gtk_adjustment_set_value(adj, 0.0);
2089 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2090 gtk_adjustment_value_changed(adj);
2092 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2093 gtk_adjustment_set_value(adj, 0.0);
2094 gtk_adjustment_value_changed(adj);
2096 sp_rtb_sensitivize( obj );
2097 }
2099 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2100 gchar const */*old_value*/, gchar const */*new_value*/,
2101 bool /*is_interactive*/, gpointer data)
2102 {
2103 GObject *tbl = G_OBJECT(data);
2105 // quit if run by the _changed callbacks
2106 if (g_object_get_data( tbl, "freeze" )) {
2107 return;
2108 }
2110 // in turn, prevent callbacks from responding
2111 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2113 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2114 SPUnit const *unit = tracker->getActiveUnit();
2116 gpointer item = g_object_get_data( tbl, "item" );
2117 if (item && SP_IS_RECT(item)) {
2118 {
2119 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2120 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2121 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2122 }
2124 {
2125 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2126 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2127 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2128 }
2130 {
2131 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2132 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2133 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2134 }
2136 {
2137 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2138 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2139 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2140 }
2141 }
2143 sp_rtb_sensitivize( tbl );
2145 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2146 }
2149 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2150 NULL, /* child_added */
2151 NULL, /* child_removed */
2152 rect_tb_event_attr_changed,
2153 NULL, /* content_changed */
2154 NULL /* order_changed */
2155 };
2157 /**
2158 * \param selection should not be NULL.
2159 */
2160 static void
2161 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2162 {
2163 int n_selected = 0;
2164 Inkscape::XML::Node *repr = NULL;
2165 SPItem *item = NULL;
2167 if ( g_object_get_data( tbl, "repr" ) ) {
2168 g_object_set_data( tbl, "item", NULL );
2169 }
2170 purge_repr_listener( tbl, tbl );
2172 for (GSList const *items = selection->itemList();
2173 items != NULL;
2174 items = items->next) {
2175 if (SP_IS_RECT((SPItem *) items->data)) {
2176 n_selected++;
2177 item = (SPItem *) items->data;
2178 repr = SP_OBJECT_REPR(item);
2179 }
2180 }
2182 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2184 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2186 if (n_selected == 0) {
2187 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2189 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2190 gtk_action_set_sensitive(w, FALSE);
2191 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2192 gtk_action_set_sensitive(h, FALSE);
2194 } else if (n_selected == 1) {
2195 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2196 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2198 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2199 gtk_action_set_sensitive(w, TRUE);
2200 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2201 gtk_action_set_sensitive(h, TRUE);
2203 if (repr) {
2204 g_object_set_data( tbl, "repr", repr );
2205 g_object_set_data( tbl, "item", item );
2206 Inkscape::GC::anchor(repr);
2207 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2208 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2209 }
2210 } else {
2211 // FIXME: implement averaging of all parameters for multiple selected
2212 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2213 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2214 sp_rtb_sensitivize( tbl );
2215 }
2216 }
2219 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2220 {
2221 EgeAdjustmentAction* eact = 0;
2223 {
2224 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2225 ege_output_action_set_use_markup( act, TRUE );
2226 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2227 g_object_set_data( holder, "mode_action", act );
2228 }
2230 // rx/ry units menu: create
2231 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2232 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2233 // fixme: add % meaning per cent of the width/height
2234 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2235 g_object_set_data( holder, "tracker", tracker );
2237 /* W */
2238 {
2239 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2240 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2241 eact = create_adjustment_action( "RectWidthAction",
2242 _("Width"), _("W:"), _("Width of rectangle"),
2243 "tools.shapes.rect", "width", 0,
2244 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2245 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2246 labels, values, G_N_ELEMENTS(labels),
2247 sp_rtb_width_value_changed );
2248 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2249 g_object_set_data( holder, "width_action", eact );
2250 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2251 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2252 }
2254 /* H */
2255 {
2256 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2257 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2258 eact = create_adjustment_action( "RectHeightAction",
2259 _("Height"), _("H:"), _("Height of rectangle"),
2260 "tools.shapes.rect", "height", 0,
2261 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2262 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2263 labels, values, G_N_ELEMENTS(labels),
2264 sp_rtb_height_value_changed );
2265 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2266 g_object_set_data( holder, "height_action", eact );
2267 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2268 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2269 }
2271 /* rx */
2272 {
2273 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2274 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2275 eact = create_adjustment_action( "RadiusXAction",
2276 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2277 "tools.shapes.rect", "rx", 0,
2278 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2279 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2280 labels, values, G_N_ELEMENTS(labels),
2281 sp_rtb_rx_value_changed);
2282 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2283 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2284 }
2286 /* ry */
2287 {
2288 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2289 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2290 eact = create_adjustment_action( "RadiusYAction",
2291 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2292 "tools.shapes.rect", "ry", 0,
2293 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2294 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2295 labels, values, G_N_ELEMENTS(labels),
2296 sp_rtb_ry_value_changed);
2297 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2298 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2299 }
2301 // add the units menu
2302 {
2303 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2304 gtk_action_group_add_action( mainActions, act );
2305 }
2307 /* Reset */
2308 {
2309 InkAction* inky = ink_action_new( "RectResetAction",
2310 _("Not rounded"),
2311 _("Make corners sharp"),
2312 "squared_corner",
2313 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2314 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2315 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2316 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2317 g_object_set_data( holder, "not_rounded", inky );
2318 }
2320 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2321 sp_rtb_sensitivize( holder );
2323 sigc::connection *connection = new sigc::connection(
2324 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2325 );
2326 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2327 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2328 }
2330 //########################
2331 //## 3D Box ##
2332 //########################
2334 // normalize angle so that it lies in the interval [0,360]
2335 static double box3d_normalize_angle (double a) {
2336 double angle = a + ((int) (a/360.0))*360;
2337 if (angle < 0) {
2338 angle += 360.0;
2339 }
2340 return angle;
2341 }
2343 static void
2344 box3d_set_button_and_adjustment(Persp3D *persp, Proj::Axis axis,
2345 GtkAdjustment *adj, GtkAction *act, GtkToggleAction *tact) {
2346 // TODO: Take all selected perspectives into account but don't touch the state button if not all of them
2347 // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states
2348 // are reset).
2349 bool is_infinite = !persp3d_VP_is_finite(persp, axis);
2351 if (is_infinite) {
2352 gtk_toggle_action_set_active(tact, TRUE);
2353 gtk_action_set_sensitive(act, TRUE);
2355 double angle = persp3d_get_infinite_angle(persp, axis);
2356 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
2357 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
2358 }
2359 } else {
2360 gtk_toggle_action_set_active(tact, FALSE);
2361 gtk_action_set_sensitive(act, FALSE);
2362 }
2363 }
2365 static void
2366 box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) {
2367 if (!persp_repr) {
2368 g_print ("No perspective given to box3d_resync_toolbar().\n");
2369 return;
2370 }
2372 GtkWidget *tbl = GTK_WIDGET(data);
2373 GtkAdjustment *adj = 0;
2374 GtkAction *act = 0;
2375 GtkToggleAction *tact = 0;
2376 Persp3D *persp = persp3d_get_from_repr(persp_repr);
2377 {
2378 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_x"));
2379 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action"));
2380 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action;
2382 box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact);
2383 }
2384 {
2385 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_y"));
2386 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action"));
2387 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action;
2389 box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact);
2390 }
2391 {
2392 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "box3d_angle_z"));
2393 act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action"));
2394 tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action;
2396 box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact);
2397 }
2398 }
2400 static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2401 gchar const */*old_value*/, gchar const */*new_value*/,
2402 bool /*is_interactive*/, gpointer data)
2403 {
2404 GtkWidget *tbl = GTK_WIDGET(data);
2406 // quit if run by the attr_changed listener
2407 // note: it used to work without the differently called freeze_ attributes (here and in
2408 // box3d_angle_value_changed()) but I now it doesn't so I'm leaving them in for now
2409 if (g_object_get_data(G_OBJECT(tbl), "freeze_angle")) {
2410 return;
2411 }
2413 // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling
2414 // sp_document_maybe_done() when the document is undo insensitive)
2415 g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(TRUE));
2417 // TODO: Only update the appropriate part of the toolbar
2418 // if (!strcmp(name, "inkscape:vp_z")) {
2419 box3d_resync_toolbar(repr, G_OBJECT(tbl));
2420 // }
2422 Persp3D *persp = persp3d_get_from_repr(repr);
2423 persp3d_update_box_reprs(persp);
2425 g_object_set_data(G_OBJECT(tbl), "freeze_attr", GINT_TO_POINTER(FALSE));
2426 }
2428 static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
2429 {
2430 NULL, /* child_added */
2431 NULL, /* child_removed */
2432 box3d_persp_tb_event_attr_changed,
2433 NULL, /* content_changed */
2434 NULL /* order_changed */
2435 };
2437 /**
2438 * \param selection Should not be NULL.
2439 */
2440 // FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
2441 // Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
2442 static void
2443 box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2444 {
2445 // Here the following should be done: If all selected boxes have finite VPs in a certain direction,
2446 // disable the angle entry fields for this direction (otherwise entering a value in them should only
2447 // update the perspectives with infinite VPs and leave the other ones untouched).
2449 Inkscape::XML::Node *persp_repr = NULL;
2450 purge_repr_listener(tbl, tbl);
2452 SPItem *item = selection->singleItem();
2453 if (item && SP_IS_BOX3D(item)) {
2454 // FIXME: Also deal with multiple selected boxes
2455 SPBox3D *box = SP_BOX3D(item);
2456 Persp3D *persp = box3d_get_perspective(box);
2457 persp_repr = SP_OBJECT_REPR(persp);
2458 if (persp_repr) {
2459 g_object_set_data(tbl, "repr", persp_repr);
2460 Inkscape::GC::anchor(persp_repr);
2461 sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl);
2462 sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl);
2463 }
2465 inkscape_active_document()->current_persp3d = persp3d_get_from_repr(persp_repr);
2466 prefs_set_string_attribute("tools.shapes.3dbox", "persp", persp_repr->attribute("id"));
2468 box3d_resync_toolbar(persp_repr, tbl);
2469 }
2470 }
2472 static void
2473 box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis)
2474 {
2475 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
2476 SPDocument *document = sp_desktop_document(desktop);
2478 // quit if run by the attr_changed listener
2479 // note: it used to work without the differently called freeze_ attributes (here and in
2480 // box3d_persp_tb_event_attr_changed()) but I now it doesn't so I'm leaving them in for now
2481 if (g_object_get_data( dataKludge, "freeze_attr" )) {
2482 return;
2483 }
2485 // in turn, prevent listener from responding
2486 g_object_set_data(dataKludge, "freeze_angle", GINT_TO_POINTER(TRUE));
2488 //Persp3D *persp = document->current_persp3d;
2489 std::set<Persp3D *> sel_persps = persp3d_currently_selected_persps (inkscape_active_event_context());
2490 if (sel_persps.empty()) {
2491 // this can happen when the document is created; we silently ignore it
2492 return;
2493 }
2494 Persp3D *persp = *(sel_persps.begin());
2496 persp->tmat.set_infinite_direction (axis, adj->value);
2497 SP_OBJECT(persp)->updateRepr();
2499 // TODO: use the correct axis here, too
2500 sp_document_maybe_done(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)"));
2502 g_object_set_data( dataKludge, "freeze_angle", GINT_TO_POINTER(FALSE) );
2503 }
2506 static void
2507 box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2508 {
2509 box3d_angle_value_changed(adj, dataKludge, Proj::X);
2510 }
2512 static void
2513 box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2514 {
2515 box3d_angle_value_changed(adj, dataKludge, Proj::Y);
2516 }
2518 static void
2519 box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge)
2520 {
2521 box3d_angle_value_changed(adj, dataKludge, Proj::Z);
2522 }
2525 static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction *box3d_angle, Proj::Axis axis )
2526 {
2527 // TODO: Take all selected perspectives into account
2528 std::set<Persp3D *> sel_persps = persp3d_currently_selected_persps (inkscape_active_event_context());
2529 if (sel_persps.empty()) {
2530 // this can happen when the document is created; we silently ignore it
2531 return;
2532 }
2533 Persp3D *persp = *(sel_persps.begin());
2535 bool set_infinite = gtk_toggle_action_get_active(act);
2536 persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE);
2537 }
2539 static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2540 {
2541 box3d_vp_state_changed(act, box3d_angle, Proj::X);
2542 }
2544 static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2545 {
2546 box3d_vp_state_changed(act, box3d_angle, Proj::Y);
2547 }
2549 static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle )
2550 {
2551 box3d_vp_state_changed(act, box3d_angle, Proj::Z);
2552 }
2554 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2555 {
2556 EgeAdjustmentAction* eact = 0;
2557 SPDocument *document = sp_desktop_document (desktop);
2558 Persp3D *persp = document->current_persp3d;
2560 EgeAdjustmentAction* box3d_angle_x = 0;
2561 EgeAdjustmentAction* box3d_angle_y = 0;
2562 EgeAdjustmentAction* box3d_angle_z = 0;
2564 /* Angle X */
2565 {
2566 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2567 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2568 eact = create_adjustment_action( "3DBoxAngleXAction",
2569 _("Angle in X direction"), _("Angle X:"),
2570 // Translators: PL is short for 'perspective line'
2571 _("Angle of PLs in X direction"),
2572 "tools.shapes.3dbox", "box3d_angle_x", 30,
2573 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
2574 -360.0, 360.0, 1.0, 10.0,
2575 labels, values, G_N_ELEMENTS(labels),
2576 box3d_angle_x_value_changed );
2577 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2578 g_object_set_data( holder, "box3d_angle_x_action", eact );
2579 box3d_angle_x = eact;
2580 }
2582 if (!persp3d_VP_is_finite(persp, Proj::X)) {
2583 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2584 } else {
2585 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2586 }
2589 /* VP X state */
2590 {
2591 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction",
2592 // Translators: VP is short for 'vanishing point'
2593 _("State of VP in X direction"),
2594 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2595 "toggle_vp_x",
2596 Inkscape::ICON_SIZE_DECORATION );
2597 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2598 g_object_set_data( holder, "box3d_vp_x_state_action", act );
2599 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x );
2600 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
2601 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_x_state", 1 ) );
2602 }
2604 /* Angle Y */
2605 {
2606 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2607 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2608 eact = create_adjustment_action( "3DBoxAngleYAction",
2609 _("Angle in Y direction"), _("Angle Y:"),
2610 // Translators: PL is short for 'perspective line'
2611 _("Angle of PLs in Y direction"),
2612 "tools.shapes.3dbox", "box3d_angle_y", 30,
2613 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2614 -360.0, 360.0, 1.0, 10.0,
2615 labels, values, G_N_ELEMENTS(labels),
2616 box3d_angle_y_value_changed );
2617 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2618 g_object_set_data( holder, "box3d_angle_y_action", eact );
2619 box3d_angle_y = eact;
2620 }
2622 if (!persp3d_VP_is_finite(persp, Proj::Y)) {
2623 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2624 } else {
2625 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2626 }
2628 /* VP Y state */
2629 {
2630 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction",
2631 // Translators: VP is short for 'vanishing point'
2632 _("State of VP in Y direction"),
2633 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2634 "toggle_vp_y",
2635 Inkscape::ICON_SIZE_DECORATION );
2636 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2637 g_object_set_data( holder, "box3d_vp_y_state_action", act );
2638 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y );
2639 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
2640 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_y_state", 1 ) );
2641 }
2643 /* Angle Z */
2644 {
2645 gchar const* labels[] = { 0, 0, 0, 0, 0, 0, 0 };
2646 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2647 eact = create_adjustment_action( "3DBoxAngleZAction",
2648 _("Angle in Z direction"), _("Angle Z:"),
2649 // Translators: PL is short for 'perspective line'
2650 _("Angle of PLs in Z direction"),
2651 "tools.shapes.3dbox", "box3d_angle_z", 30,
2652 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2653 -360.0, 360.0, 1.0, 10.0,
2654 labels, values, G_N_ELEMENTS(labels),
2655 box3d_angle_z_value_changed );
2656 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2657 g_object_set_data( holder, "box3d_angle_z_action", eact );
2658 box3d_angle_z = eact;
2659 }
2661 if (!persp3d_VP_is_finite(persp, Proj::Z)) {
2662 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2663 } else {
2664 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2665 }
2667 /* VP Z state */
2668 {
2669 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction",
2670 // Translators: VP is short for 'vanishing point'
2671 _("State of VP in Z direction"),
2672 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
2673 "toggle_vp_z",
2674 Inkscape::ICON_SIZE_DECORATION );
2675 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2676 g_object_set_data( holder, "box3d_vp_z_state_action", act );
2677 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z );
2678 gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
2679 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.shapes.3dbox", "vp_z_state", 1 ) );
2680 }
2682 sigc::connection *connection = new sigc::connection(
2683 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
2684 );
2685 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
2686 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
2687 }
2689 //########################
2690 //## Spiral ##
2691 //########################
2693 static void
2694 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2695 {
2696 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2698 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2699 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2700 }
2702 // quit if run by the attr_changed listener
2703 if (g_object_get_data( tbl, "freeze" )) {
2704 return;
2705 }
2707 // in turn, prevent listener from responding
2708 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2710 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2712 bool modmade = false;
2713 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2714 items != NULL;
2715 items = items->next)
2716 {
2717 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2718 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2719 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2720 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2721 modmade = true;
2722 }
2723 }
2725 g_free(namespaced_name);
2727 if (modmade) {
2728 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2729 _("Change spiral"));
2730 }
2732 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2733 }
2735 static void
2736 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2737 {
2738 sp_spl_tb_value_changed(adj, tbl, "revolution");
2739 }
2741 static void
2742 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2743 {
2744 sp_spl_tb_value_changed(adj, tbl, "expansion");
2745 }
2747 static void
2748 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2749 {
2750 sp_spl_tb_value_changed(adj, tbl, "t0");
2751 }
2753 static void
2754 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
2755 {
2756 GtkWidget *tbl = GTK_WIDGET(obj);
2758 GtkAdjustment *adj;
2760 // fixme: make settable
2761 gdouble rev = 5;
2762 gdouble exp = 1.0;
2763 gdouble t0 = 0.0;
2765 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2766 gtk_adjustment_set_value(adj, rev);
2767 gtk_adjustment_value_changed(adj);
2769 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2770 gtk_adjustment_set_value(adj, exp);
2771 gtk_adjustment_value_changed(adj);
2773 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2774 gtk_adjustment_set_value(adj, t0);
2775 gtk_adjustment_value_changed(adj);
2777 spinbutton_defocus(GTK_OBJECT(tbl));
2778 }
2781 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2782 gchar const */*old_value*/, gchar const */*new_value*/,
2783 bool /*is_interactive*/, gpointer data)
2784 {
2785 GtkWidget *tbl = GTK_WIDGET(data);
2787 // quit if run by the _changed callbacks
2788 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2789 return;
2790 }
2792 // in turn, prevent callbacks from responding
2793 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2795 GtkAdjustment *adj;
2796 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2797 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2799 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2800 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2802 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2803 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2805 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2806 }
2809 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2810 NULL, /* child_added */
2811 NULL, /* child_removed */
2812 spiral_tb_event_attr_changed,
2813 NULL, /* content_changed */
2814 NULL /* order_changed */
2815 };
2817 static void
2818 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2819 {
2820 int n_selected = 0;
2821 Inkscape::XML::Node *repr = NULL;
2823 purge_repr_listener( tbl, tbl );
2825 for (GSList const *items = selection->itemList();
2826 items != NULL;
2827 items = items->next)
2828 {
2829 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2830 n_selected++;
2831 repr = SP_OBJECT_REPR((SPItem *) items->data);
2832 }
2833 }
2835 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2837 if (n_selected == 0) {
2838 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2839 } else if (n_selected == 1) {
2840 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2842 if (repr) {
2843 g_object_set_data( tbl, "repr", repr );
2844 Inkscape::GC::anchor(repr);
2845 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2846 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2847 }
2848 } else {
2849 // FIXME: implement averaging of all parameters for multiple selected
2850 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2851 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2852 }
2853 }
2856 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2857 {
2858 EgeAdjustmentAction* eact = 0;
2860 {
2861 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2862 ege_output_action_set_use_markup( act, TRUE );
2863 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2864 g_object_set_data( holder, "mode_action", act );
2865 }
2867 /* Revolution */
2868 {
2869 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
2870 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2871 eact = create_adjustment_action( "SpiralRevolutionAction",
2872 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
2873 "tools.shapes.spiral", "revolution", 3.0,
2874 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2875 0.01, 1024.0, 0.1, 1.0,
2876 labels, values, G_N_ELEMENTS(labels),
2877 sp_spl_tb_revolution_value_changed, 1, 2);
2878 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2879 }
2881 /* Expansion */
2882 {
2883 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
2884 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
2885 eact = create_adjustment_action( "SpiralExpansionAction",
2886 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2887 "tools.shapes.spiral", "expansion", 1.0,
2888 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2889 0.0, 1000.0, 0.01, 1.0,
2890 labels, values, G_N_ELEMENTS(labels),
2891 sp_spl_tb_expansion_value_changed);
2892 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2893 }
2895 /* T0 */
2896 {
2897 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
2898 gdouble values[] = {0, 0.5, 0.9};
2899 eact = create_adjustment_action( "SpiralT0Action",
2900 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2901 "tools.shapes.spiral", "t0", 0.0,
2902 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2903 0.0, 0.999, 0.01, 1.0,
2904 labels, values, G_N_ELEMENTS(labels),
2905 sp_spl_tb_t0_value_changed);
2906 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2907 }
2909 /* Reset */
2910 {
2911 InkAction* inky = ink_action_new( "SpiralResetAction",
2912 _("Defaults"),
2913 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2914 GTK_STOCK_CLEAR,
2915 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2916 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2917 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2918 }
2921 sigc::connection *connection = new sigc::connection(
2922 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2923 );
2924 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2925 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2926 }
2928 //########################
2929 //## Pen/Pencil ##
2930 //########################
2933 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2934 {
2935 // Put stuff here
2936 }
2938 static void sp_pencil_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2939 {
2940 // Put stuff here
2941 }
2943 //########################
2944 //## Tweak ##
2945 //########################
2947 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2948 {
2949 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
2950 }
2952 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2953 {
2954 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
2955 }
2957 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
2958 {
2959 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2960 }
2962 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
2963 {
2964 int mode = ege_select_one_action_get_active( act );
2965 prefs_set_int_attribute("tools.tweak", "mode", mode);
2967 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
2968 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
2969 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
2970 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
2971 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
2972 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
2973 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
2974 if (doh) gtk_action_set_sensitive (doh, TRUE);
2975 if (dos) gtk_action_set_sensitive (dos, TRUE);
2976 if (dol) gtk_action_set_sensitive (dol, TRUE);
2977 if (doo) gtk_action_set_sensitive (doo, TRUE);
2978 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
2979 if (fid) gtk_action_set_sensitive (fid, FALSE);
2980 } else {
2981 if (doh) gtk_action_set_sensitive (doh, FALSE);
2982 if (dos) gtk_action_set_sensitive (dos, FALSE);
2983 if (dol) gtk_action_set_sensitive (dol, FALSE);
2984 if (doo) gtk_action_set_sensitive (doo, FALSE);
2985 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
2986 if (fid) gtk_action_set_sensitive (fid, TRUE);
2987 }
2988 }
2990 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2991 {
2992 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
2993 }
2995 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
2996 bool show = gtk_toggle_action_get_active( act );
2997 prefs_set_int_attribute ("tools.tweak", "doh", show ? 1 : 0);
2998 }
2999 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
3000 bool show = gtk_toggle_action_get_active( act );
3001 prefs_set_int_attribute ("tools.tweak", "dos", show ? 1 : 0);
3002 }
3003 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
3004 bool show = gtk_toggle_action_get_active( act );
3005 prefs_set_int_attribute ("tools.tweak", "dol", show ? 1 : 0);
3006 }
3007 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
3008 bool show = gtk_toggle_action_get_active( act );
3009 prefs_set_int_attribute ("tools.tweak", "doo", show ? 1 : 0);
3010 }
3012 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3013 {
3014 {
3015 /* Width */
3016 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
3017 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3018 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
3019 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
3020 "tools.tweak", "width", 15,
3021 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
3022 1, 100, 1.0, 10.0,
3023 labels, values, G_N_ELEMENTS(labels),
3024 sp_tweak_width_value_changed, 0.01, 0, 100 );
3025 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3026 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3027 }
3030 {
3031 /* Force */
3032 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
3033 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
3034 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
3035 _("Force"), _("Force:"), _("The force of the tweak action"),
3036 "tools.tweak", "force", 20,
3037 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
3038 1, 100, 1.0, 10.0,
3039 labels, values, G_N_ELEMENTS(labels),
3040 sp_tweak_force_value_changed, 0.01, 0, 100 );
3041 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3042 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3043 }
3045 /* Mode */
3046 {
3047 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3049 GtkTreeIter iter;
3050 gtk_list_store_append( model, &iter );
3051 gtk_list_store_set( model, &iter,
3052 0, _("Push mode"),
3053 1, _("Push parts of paths in any direction"),
3054 2, "tweak_push_mode",
3055 -1 );
3057 gtk_list_store_append( model, &iter );
3058 gtk_list_store_set( model, &iter,
3059 0, _("Shrink mode"),
3060 1, _("Shrink (inset) parts of paths"),
3061 2, "tweak_shrink_mode",
3062 -1 );
3064 gtk_list_store_append( model, &iter );
3065 gtk_list_store_set( model, &iter,
3066 0, _("Grow mode"),
3067 1, _("Grow (outset) parts of paths"),
3068 2, "tweak_grow_mode",
3069 -1 );
3071 gtk_list_store_append( model, &iter );
3072 gtk_list_store_set( model, &iter,
3073 0, _("Attract mode"),
3074 1, _("Attract parts of paths towards cursor"),
3075 2, "tweak_attract_mode",
3076 -1 );
3078 gtk_list_store_append( model, &iter );
3079 gtk_list_store_set( model, &iter,
3080 0, _("Repel mode"),
3081 1, _("Repel parts of paths from cursor"),
3082 2, "tweak_repel_mode",
3083 -1 );
3085 gtk_list_store_append( model, &iter );
3086 gtk_list_store_set( model, &iter,
3087 0, _("Roughen mode"),
3088 1, _("Roughen parts of paths"),
3089 2, "tweak_roughen_mode",
3090 -1 );
3092 gtk_list_store_append( model, &iter );
3093 gtk_list_store_set( model, &iter,
3094 0, _("Color paint mode"),
3095 1, _("Paint the tool's color upon selected objects"),
3096 2, "tweak_colorpaint_mode",
3097 -1 );
3099 gtk_list_store_append( model, &iter );
3100 gtk_list_store_set( model, &iter,
3101 0, _("Color jitter mode"),
3102 1, _("Jitter the colors of selected objects"),
3103 2, "tweak_colorjitter_mode",
3104 -1 );
3106 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
3107 g_object_set( act, "short_label", _("Mode:"), NULL );
3108 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3109 g_object_set_data( holder, "mode_action", act );
3111 ege_select_one_action_set_appearance( act, "full" );
3112 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3113 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3114 ege_select_one_action_set_icon_column( act, 2 );
3115 ege_select_one_action_set_tooltip_column( act, 1 );
3117 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3118 ege_select_one_action_set_active( act, mode );
3119 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3121 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3122 }
3124 guint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3126 {
3127 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3128 ege_output_action_set_use_markup( act, TRUE );
3129 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3130 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3131 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3132 g_object_set_data( holder, "tweak_channels_label", act);
3133 }
3135 {
3136 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3137 _("Hue"),
3138 _("In color mode, act on objects' hue"),
3139 NULL,
3140 Inkscape::ICON_SIZE_DECORATION );
3141 g_object_set( act, "short_label", _("H"), NULL );
3142 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3143 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3144 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doh", 1 ) );
3145 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3146 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3147 g_object_set_data( holder, "tweak_doh", act);
3148 }
3149 {
3150 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3151 _("Saturation"),
3152 _("In color mode, act on objects' saturation"),
3153 NULL,
3154 Inkscape::ICON_SIZE_DECORATION );
3155 g_object_set( act, "short_label", _("S"), NULL );
3156 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3157 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3158 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dos", 1 ) );
3159 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3160 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3161 g_object_set_data( holder, "tweak_dos", act );
3162 }
3163 {
3164 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3165 _("Lightness"),
3166 _("In color mode, act on objects' lightness"),
3167 NULL,
3168 Inkscape::ICON_SIZE_DECORATION );
3169 g_object_set( act, "short_label", _("L"), NULL );
3170 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3171 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3172 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dol", 1 ) );
3173 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3174 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3175 g_object_set_data( holder, "tweak_dol", act );
3176 }
3177 {
3178 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3179 _("Opacity"),
3180 _("In color mode, act on objects' opacity"),
3181 NULL,
3182 Inkscape::ICON_SIZE_DECORATION );
3183 g_object_set( act, "short_label", _("O"), NULL );
3184 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3185 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3186 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doo", 1 ) );
3187 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3188 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3189 g_object_set_data( holder, "tweak_doo", act );
3190 }
3192 { /* Fidelity */
3193 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3194 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3195 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3196 _("Fidelity"), _("Fidelity:"),
3197 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3198 "tools.tweak", "fidelity", 50,
3199 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3200 1, 100, 1.0, 10.0,
3201 labels, values, G_N_ELEMENTS(labels),
3202 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3203 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3204 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3205 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3206 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3207 g_object_set_data( holder, "tweak_fidelity", eact );
3208 }
3211 /* Use Pressure button */
3212 {
3213 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3214 _("Pressure"),
3215 _("Use the pressure of the input device to alter the force of tweak action"),
3216 "use_pressure",
3217 Inkscape::ICON_SIZE_DECORATION );
3218 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3219 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3220 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
3221 }
3223 }
3226 //########################
3227 //## Calligraphy ##
3228 //########################
3230 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3231 {
3232 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
3233 }
3235 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3236 {
3237 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
3238 }
3240 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3241 {
3242 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
3243 }
3245 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3246 {
3247 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
3248 }
3250 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3251 {
3252 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
3253 }
3255 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3256 {
3257 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
3258 }
3260 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3261 {
3262 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
3263 }
3265 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3266 {
3267 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
3268 }
3270 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3271 {
3272 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3273 }
3275 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer /*data*/ )
3276 {
3277 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
3278 }
3280 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
3281 {
3282 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3284 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
3285 }
3287 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
3288 {
3289 // FIXME: make defaults settable via Inkscape Options
3290 struct KeyValue {
3291 char const *key;
3292 double value;
3293 } const key_values[] = {
3294 {"mass", 0.02},
3295 {"wiggle", 0.0},
3296 {"angle", 30.0},
3297 {"width", 15},
3298 {"thinning", 0.1},
3299 {"tremor", 0.0},
3300 {"flatness", 0.9},
3301 {"cap_rounding", 0.0}
3302 };
3304 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
3305 KeyValue const &kv = key_values[i];
3306 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
3307 if ( adj ) {
3308 gtk_adjustment_set_value(adj, kv.value);
3309 }
3310 }
3311 }
3314 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3315 {
3316 {
3317 EgeAdjustmentAction* calligraphy_angle = 0;
3319 {
3320 /* Width */
3321 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
3322 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3323 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
3324 _("Pen Width"), _("Width:"),
3325 _("The width of the calligraphic pen (relative to the visible canvas area)"),
3326 "tools.calligraphic", "width", 15,
3327 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
3328 1, 100, 1.0, 10.0,
3329 labels, values, G_N_ELEMENTS(labels),
3330 sp_ddc_width_value_changed, 0.01, 0, 100 );
3331 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3332 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3333 }
3335 {
3336 /* Thinning */
3337 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
3338 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
3339 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
3340 _("Stroke Thinning"), _("Thinning:"),
3341 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
3342 "tools.calligraphic", "thinning", 0.1,
3343 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3344 -1.0, 1.0, 0.01, 0.1,
3345 labels, values, G_N_ELEMENTS(labels),
3346 sp_ddc_velthin_value_changed, 0.01, 2);
3347 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3348 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3349 }
3351 {
3352 /* Angle */
3353 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
3354 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3355 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
3356 _("Pen Angle"), _("Angle:"),
3357 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
3358 "tools.calligraphic", "angle", 30,
3359 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
3360 -90.0, 90.0, 1.0, 10.0,
3361 labels, values, G_N_ELEMENTS(labels),
3362 sp_ddc_angle_value_changed, 1, 0 );
3363 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3364 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3365 calligraphy_angle = eact;
3366 }
3368 {
3369 /* Fixation */
3370 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
3371 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
3372 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
3373 _("Fixation"), _("Fixation:"),
3374 _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
3375 "tools.calligraphic", "flatness", 0.9,
3376 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3377 0.0, 1.0, 0.01, 0.1,
3378 labels, values, G_N_ELEMENTS(labels),
3379 sp_ddc_flatness_value_changed, 0.01, 2 );
3380 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3381 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3382 }
3384 {
3385 /* Cap Rounding */
3386 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
3387 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
3388 // TRANSLATORS: "cap" means "end" (both start and finish) here
3389 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
3390 _("Cap rounding"), _("Caps:"),
3391 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
3392 "tools.calligraphic", "cap_rounding", 0.0,
3393 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3394 0.0, 5.0, 0.01, 0.1,
3395 labels, values, G_N_ELEMENTS(labels),
3396 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
3397 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3398 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3399 }
3401 {
3402 /* Tremor */
3403 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
3404 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
3405 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
3406 _("Stroke Tremor"), _("Tremor:"),
3407 _("Increase to make strokes rugged and trembling"),
3408 "tools.calligraphic", "tremor", 0.0,
3409 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3410 0.0, 1.0, 0.01, 0.1,
3411 labels, values, G_N_ELEMENTS(labels),
3412 sp_ddc_tremor_value_changed, 0.01, 2 );
3414 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3415 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3416 }
3418 {
3419 /* Wiggle */
3420 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
3421 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
3422 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
3423 _("Pen Wiggle"), _("Wiggle:"),
3424 _("Increase to make the pen waver and wiggle"),
3425 "tools.calligraphic", "wiggle", 0.0,
3426 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3427 0.0, 1.0, 0.01, 0.1,
3428 labels, values, G_N_ELEMENTS(labels),
3429 sp_ddc_wiggle_value_changed, 0.01, 2 );
3430 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3431 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3432 }
3434 {
3435 /* Mass */
3436 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
3437 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
3438 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
3439 _("Pen Mass"), _("Mass:"),
3440 _("Increase to make the pen drag behind, as if slowed by inertia"),
3441 "tools.calligraphic", "mass", 0.02,
3442 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3443 0.0, 1.0, 0.01, 0.1,
3444 labels, values, G_N_ELEMENTS(labels),
3445 sp_ddc_mass_value_changed, 0.01, 2 );
3446 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3447 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3448 }
3451 /* Trace Background button */
3452 {
3453 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
3454 _("Trace Background"),
3455 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
3456 "trace_background",
3457 Inkscape::ICON_SIZE_DECORATION );
3458 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3459 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
3460 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
3461 }
3463 /* Use Pressure button */
3464 {
3465 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
3466 _("Pressure"),
3467 _("Use the pressure of the input device to alter the width of the pen"),
3468 "use_pressure",
3469 Inkscape::ICON_SIZE_DECORATION );
3470 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3471 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
3472 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
3473 }
3475 /* Use Tilt button */
3476 {
3477 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
3478 _("Tilt"),
3479 _("Use the tilt of the input device to alter the angle of the pen's nib"),
3480 "use_tilt",
3481 Inkscape::ICON_SIZE_DECORATION );
3482 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3483 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
3484 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3485 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3486 }
3488 /* Reset */
3489 {
3490 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
3491 _("Defaults"),
3492 _("Reset all parameters to defaults"),
3493 GTK_STOCK_CLEAR );
3494 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
3495 gtk_action_group_add_action( mainActions, act );
3496 gtk_action_set_sensitive( act, TRUE );
3497 }
3498 }
3499 }
3502 //########################
3503 //## Circle / Arc ##
3504 //########################
3506 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
3507 {
3508 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
3509 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
3511 if (v1 == 0 && v2 == 0) {
3512 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
3513 gtk_action_set_sensitive( ocb, FALSE );
3514 gtk_action_set_sensitive( make_whole, FALSE );
3515 }
3516 } else {
3517 gtk_action_set_sensitive( ocb, TRUE );
3518 gtk_action_set_sensitive( make_whole, TRUE );
3519 }
3520 }
3522 static void
3523 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
3524 {
3525 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3527 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3528 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
3529 }
3531 // quit if run by the attr_changed listener
3532 if (g_object_get_data( tbl, "freeze" )) {
3533 return;
3534 }
3536 // in turn, prevent listener from responding
3537 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3539 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
3541 bool modmade = false;
3542 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3543 items != NULL;
3544 items = items->next)
3545 {
3546 SPItem *item = SP_ITEM(items->data);
3548 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
3550 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
3551 SPArc *arc = SP_ARC(item);
3553 if (!strcmp(value_name, "start"))
3554 ge->start = (adj->value * M_PI)/ 180;
3555 else
3556 ge->end = (adj->value * M_PI)/ 180;
3558 sp_genericellipse_normalize(ge);
3559 ((SPObject *)arc)->updateRepr();
3560 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
3562 modmade = true;
3563 }
3564 }
3566 g_free(namespaced_name);
3568 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
3570 sp_arctb_sensitivize( tbl, adj->value, other->value );
3572 if (modmade) {
3573 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
3574 _("Arc: Change start/end"));
3575 }
3577 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3578 }
3581 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
3582 {
3583 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
3584 }
3586 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
3587 {
3588 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
3589 }
3591 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
3592 {
3593 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3594 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3595 if ( ege_select_one_action_get_active( act ) != 0 ) {
3596 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
3597 } else {
3598 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
3599 }
3600 }
3602 // quit if run by the attr_changed listener
3603 if (g_object_get_data( tbl, "freeze" )) {
3604 return;
3605 }
3607 // in turn, prevent listener from responding
3608 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3610 bool modmade = false;
3612 if ( ege_select_one_action_get_active(act) != 0 ) {
3613 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3614 items != NULL;
3615 items = items->next)
3616 {
3617 if (SP_IS_ARC((SPItem *) items->data)) {
3618 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3619 repr->setAttribute("sodipodi:open", "true");
3620 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3621 modmade = true;
3622 }
3623 }
3624 } else {
3625 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3626 items != NULL;
3627 items = items->next)
3628 {
3629 if (SP_IS_ARC((SPItem *) items->data)) {
3630 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3631 repr->setAttribute("sodipodi:open", NULL);
3632 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3633 modmade = true;
3634 }
3635 }
3636 }
3638 if (modmade) {
3639 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
3640 _("Arc: Change open/closed"));
3641 }
3643 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3644 }
3646 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
3647 {
3648 GtkAdjustment *adj;
3649 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
3650 gtk_adjustment_set_value(adj, 0.0);
3651 gtk_adjustment_value_changed(adj);
3653 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
3654 gtk_adjustment_set_value(adj, 0.0);
3655 gtk_adjustment_value_changed(adj);
3657 spinbutton_defocus( GTK_OBJECT(obj) );
3658 }
3660 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3661 gchar const */*old_value*/, gchar const */*new_value*/,
3662 bool /*is_interactive*/, gpointer data)
3663 {
3664 GObject *tbl = G_OBJECT(data);
3666 // quit if run by the _changed callbacks
3667 if (g_object_get_data( tbl, "freeze" )) {
3668 return;
3669 }
3671 // in turn, prevent callbacks from responding
3672 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3674 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
3675 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
3677 GtkAdjustment *adj1,*adj2;
3678 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
3679 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
3680 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
3681 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
3683 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
3685 char const *openstr = NULL;
3686 openstr = repr->attribute("sodipodi:open");
3687 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
3689 if (openstr) {
3690 ege_select_one_action_set_active( ocb, 1 );
3691 } else {
3692 ege_select_one_action_set_active( ocb, 0 );
3693 }
3695 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3696 }
3698 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
3699 NULL, /* child_added */
3700 NULL, /* child_removed */
3701 arc_tb_event_attr_changed,
3702 NULL, /* content_changed */
3703 NULL /* order_changed */
3704 };
3707 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3708 {
3709 int n_selected = 0;
3710 Inkscape::XML::Node *repr = NULL;
3712 purge_repr_listener( tbl, tbl );
3714 for (GSList const *items = selection->itemList();
3715 items != NULL;
3716 items = items->next)
3717 {
3718 if (SP_IS_ARC((SPItem *) items->data)) {
3719 n_selected++;
3720 repr = SP_OBJECT_REPR((SPItem *) items->data);
3721 }
3722 }
3724 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3726 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3727 if (n_selected == 0) {
3728 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3729 } else if (n_selected == 1) {
3730 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3731 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3733 if (repr) {
3734 g_object_set_data( tbl, "repr", repr );
3735 Inkscape::GC::anchor(repr);
3736 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
3737 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
3738 }
3739 } else {
3740 // FIXME: implement averaging of all parameters for multiple selected
3741 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3742 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3743 sp_arctb_sensitivize( tbl, 1, 0 );
3744 }
3745 }
3748 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3749 {
3750 EgeAdjustmentAction* eact = 0;
3753 {
3754 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
3755 ege_output_action_set_use_markup( act, TRUE );
3756 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3757 g_object_set_data( holder, "mode_action", act );
3758 }
3760 /* Start */
3761 {
3762 eact = create_adjustment_action( "ArcStartAction",
3763 _("Start"), _("Start:"),
3764 _("The angle (in degrees) from the horizontal to the arc's start point"),
3765 "tools.shapes.arc", "start", 0.0,
3766 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
3767 -360.0, 360.0, 1.0, 10.0,
3768 0, 0, 0,
3769 sp_arctb_start_value_changed);
3770 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3771 }
3773 /* End */
3774 {
3775 eact = create_adjustment_action( "ArcEndAction",
3776 _("End"), _("End:"),
3777 _("The angle (in degrees) from the horizontal to the arc's end point"),
3778 "tools.shapes.arc", "end", 0.0,
3779 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3780 -360.0, 360.0, 1.0, 10.0,
3781 0, 0, 0,
3782 sp_arctb_end_value_changed);
3783 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3784 }
3786 /* Segments / Pie checkbox */
3787 {
3788 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3790 GtkTreeIter iter;
3791 gtk_list_store_append( model, &iter );
3792 gtk_list_store_set( model, &iter,
3793 0, _("Closed arc"),
3794 1, _("Switch to segment (closed shape with two radii)"),
3795 2, "circle_closed_arc",
3796 -1 );
3798 gtk_list_store_append( model, &iter );
3799 gtk_list_store_set( model, &iter,
3800 0, _("Open Arc"),
3801 1, _("Switch to arc (unclosed shape)"),
3802 2, "circle_open_arc",
3803 -1 );
3805 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
3806 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3807 g_object_set_data( holder, "open_action", act );
3809 ege_select_one_action_set_appearance( act, "full" );
3810 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3811 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3812 ege_select_one_action_set_icon_column( act, 2 );
3813 ege_select_one_action_set_tooltip_column( act, 1 );
3815 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
3816 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
3817 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
3818 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
3819 }
3821 /* Make Whole */
3822 {
3823 InkAction* inky = ink_action_new( "ArcResetAction",
3824 _("Make whole"),
3825 _("Make the shape a whole ellipse, not arc or segment"),
3826 "reset_circle",
3827 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3828 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
3829 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3830 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3831 g_object_set_data( holder, "make_whole", inky );
3832 }
3834 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
3835 // sensitivize make whole and open checkbox
3836 {
3837 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
3838 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
3839 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
3840 }
3843 sigc::connection *connection = new sigc::connection(
3844 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
3845 );
3846 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3847 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3848 }
3853 // toggle button callbacks and updaters
3855 //########################
3856 //## Dropper ##
3857 //########################
3859 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
3860 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
3861 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
3862 if ( set_action ) {
3863 if ( gtk_toggle_action_get_active( act ) ) {
3864 gtk_action_set_sensitive( set_action, TRUE );
3865 } else {
3866 gtk_action_set_sensitive( set_action, FALSE );
3867 }
3868 }
3870 spinbutton_defocus(GTK_OBJECT(tbl));
3871 }
3873 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
3874 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3875 spinbutton_defocus(GTK_OBJECT(tbl));
3876 }
3879 /**
3880 * Dropper auxiliary toolbar construction and setup.
3881 *
3882 * TODO: Would like to add swatch of current color.
3883 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3884 * can drag and drop places. Will provide a nice mixing palette.
3885 */
3886 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3887 {
3888 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
3890 {
3891 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
3892 _("Pick alpha"),
3893 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
3894 "color_alpha_get",
3895 Inkscape::ICON_SIZE_DECORATION );
3896 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3897 g_object_set_data( holder, "pick_action", act );
3898 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
3899 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
3900 }
3902 {
3903 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
3904 _("Set alpha"),
3905 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
3906 "color_alpha_set",
3907 Inkscape::ICON_SIZE_DECORATION );
3908 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3909 g_object_set_data( holder, "set_action", act );
3910 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
3911 // make sure it's disabled if we're not picking alpha
3912 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
3913 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
3914 }
3915 }
3918 //########################
3919 //## Text Toolbox ##
3920 //########################
3921 /*
3922 static void
3923 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3924 {
3925 //Call back for letter sizing spinbutton
3926 }
3928 static void
3929 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3930 {
3931 //Call back for line height spinbutton
3932 }
3934 static void
3935 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3936 {
3937 //Call back for horizontal kerning spinbutton
3938 }
3940 static void
3941 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3942 {
3943 //Call back for vertical kerning spinbutton
3944 }
3946 static void
3947 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3948 {
3949 //Call back for letter rotation spinbutton
3950 }*/
3952 namespace {
3954 bool visible = false;
3956 void
3957 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
3958 {
3959 SPStyle *query =
3960 sp_style_new (SP_ACTIVE_DOCUMENT);
3962 int result_fontspec =
3963 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
3965 int result_family =
3966 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3968 int result_style =
3969 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3971 int result_numbers =
3972 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3974 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3976 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3977 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3978 {
3979 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3981 if (repr)
3982 {
3983 sp_style_read_from_repr (query, repr);
3984 }
3985 else
3986 {
3987 return;
3988 }
3989 }
3991 if (query->text)
3992 {
3993 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3994 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3995 gtk_entry_set_text (GTK_ENTRY (entry), "");
3997 } else if (query->text->font_specification.value || query->text->font_family.value) {
3999 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
4001 // Get the font that corresponds
4002 Glib::ustring familyName;
4004 font_instance * font = font_factory::Default()->FaceFromStyle(query);
4005 if (font) {
4006 familyName = font_factory::Default()->GetUIFamilyString(font->descr);
4007 font->Unref();
4008 font = NULL;
4009 }
4011 gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
4013 Gtk::TreePath path;
4014 try {
4015 path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
4016 } catch (...) {
4017 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
4018 return;
4019 }
4021 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4022 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4024 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
4026 gtk_tree_selection_select_path (tselection, path.gobj());
4027 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4029 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
4030 }
4032 //Size
4033 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4034 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
4035 g_object_set_data (tbl, "size-block", gpointer(1));
4036 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
4037 g_object_set_data (tbl, "size-block", gpointer(0));
4038 free (str);
4040 //Anchor
4041 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
4042 {
4043 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
4044 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4045 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4046 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4047 }
4048 else
4049 {
4050 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
4051 {
4052 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
4053 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4054 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4055 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4056 }
4057 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
4058 {
4059 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
4060 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4061 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4062 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4063 }
4064 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
4065 {
4066 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
4067 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4068 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4069 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4070 }
4071 }
4073 //Style
4074 {
4075 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
4077 gboolean active = gtk_toggle_button_get_active (button);
4078 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
4080 if (active != check)
4081 {
4082 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4083 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4084 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4085 }
4086 }
4088 {
4089 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
4091 gboolean active = gtk_toggle_button_get_active (button);
4092 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
4094 if (active != check)
4095 {
4096 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4097 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4098 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4099 }
4100 }
4102 //Orientation
4103 //locking both buttons, changing one affect all group (both)
4104 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
4105 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4107 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
4108 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
4110 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
4111 {
4112 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4113 }
4114 else
4115 {
4116 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
4117 }
4118 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4119 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
4120 }
4122 sp_style_unref(query);
4123 }
4125 void
4126 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
4127 {
4128 sp_text_toolbox_selection_changed (selection, tbl);
4129 }
4131 void
4132 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4133 {
4134 sp_text_toolbox_selection_changed (NULL, tbl);
4135 }
4137 void
4138 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4139 GObject *tbl)
4140 {
4141 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4142 GtkTreeModel *model = 0;
4143 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4144 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4145 GtkTreeIter iter;
4146 char *family = 0;
4148 (void)popdown;
4150 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4151 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4153 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
4154 return;
4155 }
4157 gtk_tree_model_get (model, &iter, 0, &family, -1);
4159 if (g_object_get_data (G_OBJECT (selection), "block"))
4160 {
4161 gtk_entry_set_text (GTK_ENTRY (entry), family);
4162 return;
4163 }
4165 gtk_entry_set_text (GTK_ENTRY (entry), family);
4167 SPStyle *query =
4168 sp_style_new (SP_ACTIVE_DOCUMENT);
4170 int result_fontspec =
4171 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4173 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
4175 SPCSSAttr *css = sp_repr_css_attr_new ();
4178 // First try to get the font spec from the stored value
4179 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
4181 if (fontSpec.empty()) {
4182 // Construct a new font specification if it does not yet exist
4183 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
4184 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
4185 fontFromStyle->Unref();
4186 }
4188 if (!fontSpec.empty()) {
4189 Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
4190 if (!newFontSpec.empty() && fontSpec != newFontSpec) {
4191 font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
4192 if (font) {
4193 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
4195 // Set all the these just in case they were altered when finding the best
4196 // match for the new family and old style...
4198 gchar c[256];
4200 font->Family(c, 256);
4201 sp_repr_css_set_property (css, "font-family", c);
4203 font->Attribute( "weight", c, 256);
4204 sp_repr_css_set_property (css, "font-weight", c);
4206 font->Attribute("style", c, 256);
4207 sp_repr_css_set_property (css, "font-style", c);
4209 font->Attribute("stretch", c, 256);
4210 sp_repr_css_set_property (css, "font-stretch", c);
4212 font->Attribute("variant", c, 256);
4213 sp_repr_css_set_property (css, "font-variant", c);
4215 font->Unref();
4216 }
4217 }
4218 }
4220 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4221 if (result_fontspec == QUERY_STYLE_NOTHING)
4222 {
4223 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4224 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
4225 }
4226 else
4227 {
4228 sp_desktop_set_style (desktop, css, true, true);
4229 }
4231 sp_style_unref(query);
4233 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4234 _("Text: Change font family"));
4235 sp_repr_css_attr_unref (css);
4236 free (family);
4237 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4239 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4240 }
4242 void
4243 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
4244 GObject *tbl)
4245 {
4246 const char *family = gtk_entry_get_text (entry);
4248 try {
4249 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
4250 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4251 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4252 gtk_tree_selection_select_path (selection, path.gobj());
4253 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4254 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4255 } catch (...) {
4256 if (family && strlen (family))
4257 {
4258 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4259 }
4260 }
4261 }
4263 void
4264 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
4265 gpointer data)
4266 {
4267 if (g_object_get_data (G_OBJECT (button), "block")) return;
4268 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
4269 int prop = GPOINTER_TO_INT(data);
4271 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4272 SPCSSAttr *css = sp_repr_css_attr_new ();
4274 switch (prop)
4275 {
4276 case 0:
4277 {
4278 sp_repr_css_set_property (css, "text-anchor", "start");
4279 sp_repr_css_set_property (css, "text-align", "start");
4280 break;
4281 }
4282 case 1:
4283 {
4284 sp_repr_css_set_property (css, "text-anchor", "middle");
4285 sp_repr_css_set_property (css, "text-align", "center");
4286 break;
4287 }
4289 case 2:
4290 {
4291 sp_repr_css_set_property (css, "text-anchor", "end");
4292 sp_repr_css_set_property (css, "text-align", "end");
4293 break;
4294 }
4296 case 3:
4297 {
4298 sp_repr_css_set_property (css, "text-anchor", "start");
4299 sp_repr_css_set_property (css, "text-align", "justify");
4300 break;
4301 }
4302 }
4304 SPStyle *query =
4305 sp_style_new (SP_ACTIVE_DOCUMENT);
4306 int result_numbers =
4307 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4309 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4310 if (result_numbers == QUERY_STYLE_NOTHING)
4311 {
4312 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4313 }
4315 sp_style_unref(query);
4317 sp_desktop_set_style (desktop, css, true, true);
4318 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4319 _("Text: Change alignment"));
4320 sp_repr_css_attr_unref (css);
4322 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4323 }
4325 void
4326 sp_text_toolbox_style_toggled (GtkToggleButton *button,
4327 gpointer data)
4328 {
4329 if (g_object_get_data (G_OBJECT (button), "block")) return;
4331 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4332 SPCSSAttr *css = sp_repr_css_attr_new ();
4333 int prop = GPOINTER_TO_INT(data);
4334 bool active = gtk_toggle_button_get_active (button);
4336 SPStyle *query =
4337 sp_style_new (SP_ACTIVE_DOCUMENT);
4339 int result_fontspec =
4340 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4342 int result_family =
4343 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
4345 int result_style =
4346 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
4348 int result_numbers =
4349 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4351 Glib::ustring fontSpec = query->text->font_specification.set ? query->text->font_specification.value : "";
4352 Glib::ustring newFontSpec = "";
4354 if (fontSpec.empty()) {
4355 // Construct a new font specification if it does not yet exist
4356 font_instance * fontFromStyle = font_factory::Default()->FaceFromStyle(query);
4357 fontSpec = font_factory::Default()->ConstructFontSpecification(fontFromStyle);
4358 fontFromStyle->Unref();
4359 }
4361 switch (prop)
4362 {
4363 case 0:
4364 {
4365 if (!fontSpec.empty()) {
4366 newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
4367 }
4368 if (fontSpec != newFontSpec) {
4369 // Don't even set the bold if the font didn't exist on the system
4370 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
4371 }
4372 break;
4373 }
4375 case 1:
4376 {
4377 if (!fontSpec.empty()) {
4378 newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
4379 }
4380 if (fontSpec != newFontSpec) {
4381 // Don't even set the italic if the font didn't exist on the system
4382 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
4383 }
4384 break;
4385 }
4386 }
4388 if (!newFontSpec.empty()) {
4389 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
4390 }
4392 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4393 if (result_fontspec == QUERY_STYLE_NOTHING)
4394 {
4395 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4396 }
4398 sp_style_unref(query);
4400 sp_desktop_set_style (desktop, css, true, true);
4401 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4402 _("Text: Change font style"));
4403 sp_repr_css_attr_unref (css);
4405 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4406 }
4408 void
4409 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
4410 gpointer data)
4411 {
4412 if (g_object_get_data (G_OBJECT (button), "block")) {
4413 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4414 return;
4415 }
4417 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4418 SPCSSAttr *css = sp_repr_css_attr_new ();
4419 int prop = GPOINTER_TO_INT(data);
4421 switch (prop)
4422 {
4423 case 0:
4424 {
4425 sp_repr_css_set_property (css, "writing-mode", "lr");
4426 break;
4427 }
4429 case 1:
4430 {
4431 sp_repr_css_set_property (css, "writing-mode", "tb");
4432 break;
4433 }
4434 }
4436 SPStyle *query =
4437 sp_style_new (SP_ACTIVE_DOCUMENT);
4438 int result_numbers =
4439 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4441 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4442 if (result_numbers == QUERY_STYLE_NOTHING)
4443 {
4444 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4445 }
4447 sp_desktop_set_style (desktop, css, true, true);
4448 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4449 _("Text: Change orientation"));
4450 sp_repr_css_attr_unref (css);
4452 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4453 }
4455 gboolean
4456 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4457 {
4458 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4459 if (!desktop) return FALSE;
4461 switch (get_group0_keyval (event)) {
4462 case GDK_Escape: // defocus
4463 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4464 sp_text_toolbox_selection_changed (NULL, tbl); // update
4465 return TRUE; // I consumed the event
4466 break;
4467 }
4468 return FALSE;
4469 }
4471 gboolean
4472 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
4473 {
4474 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4475 if (!desktop) return FALSE;
4477 switch (get_group0_keyval (event)) {
4478 case GDK_KP_Enter:
4479 case GDK_Return:
4480 case GDK_Escape: // defocus
4481 gtk_widget_hide (w);
4482 visible = false;
4483 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4484 return TRUE; // I consumed the event
4485 break;
4486 }
4487 return FALSE;
4488 }
4491 void
4492 sp_text_toolbox_size_changed (GtkComboBox *cbox,
4493 GObject *tbl)
4494 {
4495 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4497 if (g_object_get_data (tbl, "size-block")) return;
4499 // If this is not from selecting a size in the list (in which case get_active will give the
4500 // index of the selected item, otherwise -1) and not from user pressing Enter/Return, do not
4501 // process this event. This fixes GTK's stupid insistence on sending an activate change every
4502 // time any character gets typed or deleted, which made this control nearly unusable in 0.45.
4503 if (gtk_combo_box_get_active (cbox) < 0 && !g_object_get_data (tbl, "enter-pressed"))
4504 return;
4506 gchar *endptr;
4507 gdouble value = -1;
4508 char *text = gtk_combo_box_get_active_text (cbox);
4509 if (text) {
4510 value = g_strtod (text, &endptr);
4511 if (endptr == text) // conversion failed, non-numeric input
4512 value = -1;
4513 free (text);
4514 }
4515 if (value <= 0) {
4516 return; // could not parse value
4517 }
4519 SPCSSAttr *css = sp_repr_css_attr_new ();
4520 Inkscape::CSSOStringStream osfs;
4521 osfs << value;
4522 sp_repr_css_set_property (css, "font-size", osfs.str().c_str());
4524 SPStyle *query =
4525 sp_style_new (SP_ACTIVE_DOCUMENT);
4526 int result_numbers =
4527 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4529 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4530 if (result_numbers == QUERY_STYLE_NOTHING)
4531 {
4532 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4533 }
4535 sp_style_unref(query);
4537 sp_desktop_set_style (desktop, css, true, true);
4538 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
4539 _("Text: Change font size"));
4540 sp_repr_css_attr_unref (css);
4542 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4543 }
4545 gboolean
4546 sp_text_toolbox_size_focusout (GtkWidget */*w*/, GdkEventFocus *event, GObject *tbl)
4547 {
4548 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4549 if (!desktop) return FALSE;
4551 if (!g_object_get_data (tbl, "esc-pressed")) {
4552 g_object_set_data (tbl, "enter-pressed", gpointer(1));
4553 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4554 sp_text_toolbox_size_changed (cbox, tbl);
4555 g_object_set_data (tbl, "enter-pressed", gpointer(0));
4556 }
4557 return FALSE; // I consumed the event
4558 }
4561 gboolean
4562 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4563 {
4564 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4565 if (!desktop) return FALSE;
4567 switch (get_group0_keyval (event)) {
4568 case GDK_Escape: // defocus
4569 g_object_set_data (tbl, "esc-pressed", gpointer(1));
4570 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4571 g_object_set_data (tbl, "esc-pressed", gpointer(0));
4572 return TRUE; // I consumed the event
4573 break;
4574 case GDK_Return: // defocus
4575 case GDK_KP_Enter:
4576 g_object_set_data (tbl, "enter-pressed", gpointer(1));
4577 GtkComboBox *cbox = GTK_COMBO_BOX(g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4578 sp_text_toolbox_size_changed (cbox, tbl);
4579 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4580 g_object_set_data (tbl, "enter-pressed", gpointer(0));
4581 return TRUE; // I consumed the event
4582 break;
4583 }
4584 return FALSE;
4585 }
4587 void
4588 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
4589 GObject *tbl)
4590 {
4591 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4592 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4593 int x, y;
4595 if (!visible)
4596 {
4597 gdk_window_get_origin (widget->window, &x, &y);
4598 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
4599 gtk_widget_show_all (popdown);
4601 gdk_pointer_grab (widget->window, TRUE,
4602 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
4603 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
4604 GDK_POINTER_MOTION_MASK),
4605 NULL, NULL, GDK_CURRENT_TIME);
4607 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
4609 visible = true;
4610 }
4611 else
4612 {
4613 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4614 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4615 gtk_widget_hide (popdown);
4616 visible = false;
4617 }
4618 }
4620 gboolean
4621 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
4622 GdkEventFocus */*event*/,
4623 GObject */*tbl*/)
4624 {
4625 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
4626 return FALSE;
4627 }
4629 gboolean
4630 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
4631 GdkEventFocus */*event*/,
4632 GObject */*tbl*/)
4633 {
4634 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4636 gtk_widget_hide (popdown);
4637 visible = false;
4638 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4639 return TRUE;
4640 }
4642 void
4643 cell_data_func (GtkTreeViewColumn */*column*/,
4644 GtkCellRenderer *cell,
4645 GtkTreeModel *tree_model,
4646 GtkTreeIter *iter,
4647 gpointer /*data*/)
4648 {
4649 char *family,
4650 *family_escaped,
4651 *sample_escaped;
4653 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
4655 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
4657 family_escaped = g_markup_escape_text (family, -1);
4658 sample_escaped = g_markup_escape_text (sample, -1);
4660 std::stringstream markup;
4661 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
4662 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
4664 free (family);
4665 free (family_escaped);
4666 free (sample_escaped);
4667 }
4669 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
4670 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
4671 if (completion) {
4672 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
4673 g_object_unref (completion);
4674 }
4675 }
4677 GtkWidget*
4678 sp_text_toolbox_new (SPDesktop *desktop)
4679 {
4680 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
4682 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4683 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4685 GtkTooltips *tt = gtk_tooltips_new();
4686 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4688 ////////////Family
4689 //Window
4690 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4691 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4693 //Entry
4694 GtkWidget *entry = gtk_entry_new ();
4695 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4696 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4697 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4698 gtk_entry_completion_set_text_column (completion, 0);
4699 gtk_entry_completion_set_minimum_key_length (completion, 1);
4700 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4701 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4702 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4703 aux_toolbox_space (tbl, 1);
4704 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
4705 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
4707 //Button
4708 GtkWidget *button = gtk_button_new ();
4709 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
4710 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
4712 //Popdown
4713 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
4714 GtkWidget *treeview = gtk_tree_view_new ();
4716 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4717 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
4718 gtk_tree_view_column_pack_start (column, cell, FALSE);
4719 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
4720 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
4721 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4723 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
4724 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
4725 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
4727 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
4729 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
4730 gtk_container_add (GTK_CONTAINER (sw), treeview);
4732 gtk_container_add (GTK_CONTAINER (window), sw);
4733 gtk_widget_set_size_request (window, 300, 450);
4735 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
4736 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
4737 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
4739 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
4741 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
4742 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
4744 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
4745 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
4747 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
4748 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
4749 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
4750 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
4751 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
4753 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
4754 aux_toolbox_space (tbl, 1);
4755 GtkWidget *box = gtk_event_box_new ();
4756 gtk_container_add (GTK_CONTAINER (box), image);
4757 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
4758 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
4759 GtkTooltips *tooltips = gtk_tooltips_new ();
4760 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
4761 gtk_widget_hide (GTK_WIDGET (box));
4762 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
4764 ////////////Size
4765 const char *sizes[] = {
4766 "4", "6", "8", "9", "10", "11", "12", "13", "14",
4767 "16", "18", "20", "22", "24", "28",
4768 "32", "36", "40", "48", "56", "64", "72", "144"
4769 };
4771 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
4772 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
4773 gtk_widget_set_size_request (cbox, 80, -1);
4774 aux_toolbox_space (tbl, 1);
4775 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
4776 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
4777 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
4778 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), tbl);
4779 gtk_signal_connect(GTK_OBJECT(gtk_bin_get_child(GTK_BIN(cbox))), "focus-out-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_focusout), tbl);
4781 //spacer
4782 aux_toolbox_space (tbl, 4);
4783 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4785 ////////////Text anchor
4786 GtkWidget *group = gtk_radio_button_new (NULL);
4787 GtkWidget *row = gtk_hbox_new (FALSE, 4);
4788 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
4790 // left
4791 GtkWidget *rbutton = group;
4792 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4793 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4794 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4796 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4797 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
4798 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
4799 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
4801 // center
4802 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4803 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4804 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
4805 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4807 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4808 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
4809 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
4810 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
4812 // right
4813 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4814 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4815 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4816 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4818 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4819 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
4820 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
4821 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
4823 // fill
4824 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4825 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4826 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
4827 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4829 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4830 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
4831 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
4832 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
4834 aux_toolbox_space (tbl, 1);
4835 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4837 //spacer
4838 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4840 ////////////Text style
4841 row = gtk_hbox_new (FALSE, 4);
4843 // bold
4844 rbutton = gtk_toggle_button_new ();
4845 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4846 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
4847 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4848 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
4850 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4851 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
4852 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
4854 // italic
4855 rbutton = gtk_toggle_button_new ();
4856 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4857 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
4858 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4859 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
4861 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4862 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
4863 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
4865 aux_toolbox_space (tbl, 1);
4866 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4868 //spacer
4869 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4871 ////////////Text orientation
4872 group = gtk_radio_button_new (NULL);
4873 row = gtk_hbox_new (FALSE, 4);
4874 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4876 // horizontal
4877 rbutton = group;
4878 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4879 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4880 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4881 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4883 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4884 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4885 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4887 // vertical
4888 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4889 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4890 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4891 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4892 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4894 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4895 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4896 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4897 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4900 //watch selection
4901 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4903 sigc::connection *c_selection_changed =
4904 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4905 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4906 pool->add_connection ("selection-changed", c_selection_changed);
4908 sigc::connection *c_selection_modified =
4909 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4910 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4911 pool->add_connection ("selection-modified", c_selection_modified);
4913 sigc::connection *c_subselection_changed =
4914 new sigc::connection (desktop->connectToolSubselectionChanged
4915 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4916 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4918 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4921 gtk_widget_show_all (tbl);
4922 return tbl;
4924 } // end of sp_text_toolbox_new()
4926 }//<unnamed> namespace
4929 //#########################
4930 //## Connector ##
4931 //#########################
4933 static void sp_connector_path_set_avoid(void)
4934 {
4935 cc_selection_set_avoid(true);
4936 }
4939 static void sp_connector_path_set_ignore(void)
4940 {
4941 cc_selection_set_avoid(false);
4942 }
4946 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4947 {
4948 // quit if run by the _changed callbacks
4949 if (g_object_get_data( tbl, "freeze" )) {
4950 return;
4951 }
4953 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4954 SPDocument *doc = sp_desktop_document(desktop);
4956 if (!sp_document_get_undo_sensitive(doc))
4957 {
4958 return;
4959 }
4961 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4963 if ( repr->attribute("inkscape:connector-spacing") ) {
4964 gdouble priorValue = gtk_adjustment_get_value(adj);
4965 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4966 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4967 return;
4968 }
4969 } else if ( adj->value == defaultConnSpacing ) {
4970 return;
4971 }
4973 // in turn, prevent callbacks from responding
4974 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4976 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4977 SP_OBJECT(desktop->namedview)->updateRepr();
4979 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4980 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4981 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4982 NR::Matrix m = NR::identity();
4983 avoid_item_move(&m, item);
4984 }
4986 if (items) {
4987 g_slist_free(items);
4988 }
4990 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4991 _("Change connector spacing"));
4993 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4995 spinbutton_defocus(GTK_OBJECT(tbl));
4996 }
4998 static void sp_connector_graph_layout(void)
4999 {
5000 if (!SP_ACTIVE_DESKTOP) return;
5002 // hack for clones, see comment in align-and-distribute.cpp
5003 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
5004 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
5006 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
5008 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
5010 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
5011 }
5013 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
5014 {
5015 if ( gtk_toggle_action_get_active( act ) ) {
5016 prefs_set_string_attribute("tools.connector", "directedlayout",
5017 "true");
5018 } else {
5019 prefs_set_string_attribute("tools.connector", "directedlayout",
5020 "false");
5021 }
5022 }
5024 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
5025 {
5026 if ( gtk_toggle_action_get_active( act ) ) {
5027 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
5028 "true");
5029 } else {
5030 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
5031 "false");
5032 }
5033 }
5036 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
5037 {
5038 prefs_set_double_attribute("tools.connector", "length", adj->value);
5039 spinbutton_defocus(GTK_OBJECT(tbl));
5040 }
5042 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
5043 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
5044 bool /*is_interactive*/, gpointer data)
5045 {
5046 GtkWidget *tbl = GTK_WIDGET(data);
5048 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
5049 return;
5050 }
5051 if (strcmp(name, "inkscape:connector-spacing") != 0) {
5052 return;
5053 }
5055 GtkAdjustment *adj = (GtkAdjustment*)
5056 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
5057 gdouble spacing = defaultConnSpacing;
5058 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
5060 gtk_adjustment_set_value(adj, spacing);
5061 }
5064 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
5065 NULL, /* child_added */
5066 NULL, /* child_removed */
5067 connector_tb_event_attr_changed,
5068 NULL, /* content_changed */
5069 NULL /* order_changed */
5070 };
5073 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
5074 {
5075 {
5076 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
5077 _("Avoid"),
5078 _("Make connectors avoid selected objects"),
5079 "connector_avoid",
5080 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5081 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
5082 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5083 }
5085 {
5086 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
5087 _("Ignore"),
5088 _("Make connectors ignore selected objects"),
5089 "connector_ignore",
5090 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5091 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
5092 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5093 }
5095 EgeAdjustmentAction* eact = 0;
5097 // Spacing spinbox
5098 eact = create_adjustment_action( "ConnectorSpacingAction",
5099 _("Connector Spacing"), _("Spacing:"),
5100 _("The amount of space left around objects by auto-routing connectors"),
5101 "tools.connector", "spacing", defaultConnSpacing,
5102 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
5103 0, 100, 1.0, 10.0,
5104 0, 0, 0,
5105 connector_spacing_changed, 1, 0 );
5106 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5108 // Graph (connector network) layout
5109 {
5110 InkAction* inky = ink_action_new( "ConnectorGraphAction",
5111 _("Graph"),
5112 _("Nicely arrange selected connector network"),
5113 "graph_layout",
5114 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5115 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
5116 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5117 }
5119 // Default connector length spinbox
5120 eact = create_adjustment_action( "ConnectorLengthAction",
5121 _("Connector Length"), _("Length:"),
5122 _("Ideal length for connectors when layout is applied"),
5123 "tools.connector", "length", 100,
5124 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
5125 10, 1000, 10.0, 100.0,
5126 0, 0, 0,
5127 connector_length_changed, 1, 0 );
5128 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5131 // Directed edges toggle button
5132 {
5133 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
5134 _("Downwards"),
5135 _("Make connectors with end-markers (arrows) point downwards"),
5136 "directed_graph",
5137 Inkscape::ICON_SIZE_DECORATION );
5138 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5140 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
5141 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5142 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5144 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
5145 }
5147 // Avoid overlaps toggle button
5148 {
5149 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
5150 _("Remove overlaps"),
5151 _("Do not allow overlapping shapes"),
5152 "remove_overlaps",
5153 Inkscape::ICON_SIZE_DECORATION );
5154 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5156 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
5157 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5158 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5160 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
5161 }
5163 // Code to watch for changes to the connector-spacing attribute in
5164 // the XML.
5165 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5166 g_assert(repr != NULL);
5168 purge_repr_listener( holder, holder );
5170 if (repr) {
5171 g_object_set_data( holder, "repr", repr );
5172 Inkscape::GC::anchor(repr);
5173 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
5174 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
5175 }
5176 } // end of sp_connector_toolbox_prep()
5179 //#########################
5180 //## Paintbucket ##
5181 //#########################
5183 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
5184 {
5185 gint channels = ege_select_one_action_get_active( act );
5186 flood_channels_set_channels( channels );
5187 }
5189 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
5190 {
5191 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
5192 }
5194 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
5195 {
5196 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
5197 }
5199 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
5200 {
5201 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
5202 SPUnit const *unit = tracker->getActiveUnit();
5204 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
5206 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
5207 }
5209 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
5210 {
5211 // FIXME: make defaults settable via Inkscape Options
5212 struct KeyValue {
5213 char const *key;
5214 double value;
5215 } const key_values[] = {
5216 {"threshold", 15},
5217 {"offset", 0.0}
5218 };
5220 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
5221 KeyValue const &kv = key_values[i];
5222 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
5223 if ( adj ) {
5224 gtk_adjustment_set_value(adj, kv.value);
5225 }
5226 }
5228 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
5229 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
5230 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
5231 ege_select_one_action_set_active( autogap_action, 0 );
5232 }
5234 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5235 {
5236 EgeAdjustmentAction* eact = 0;
5238 {
5239 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5241 GList* items = 0;
5242 gint count = 0;
5243 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
5244 {
5245 GtkTreeIter iter;
5246 gtk_list_store_append( model, &iter );
5247 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5248 count++;
5249 }
5250 g_list_free( items );
5251 items = 0;
5252 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
5253 g_object_set( act1, "short_label", _("Fill by:"), NULL );
5254 ege_select_one_action_set_appearance( act1, "compact" );
5255 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
5256 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
5257 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
5258 g_object_set_data( holder, "channels_action", act1 );
5259 }
5261 // Spacing spinbox
5262 {
5263 eact = create_adjustment_action(
5264 "ThresholdAction",
5265 _("Fill Threshold"), _("Threshold:"),
5266 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
5267 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
5268 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
5269 0, 0, 0,
5270 paintbucket_threshold_changed, 1, 0 );
5272 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5273 }
5275 // Create the units menu.
5276 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
5277 tracker->setActiveUnit(sp_unit_get_by_abbreviation(prefs_get_string_attribute("tools.paintbucket", "offsetunits")));
5278 g_object_set_data( holder, "tracker", tracker );
5279 {
5280 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
5281 gtk_action_group_add_action( mainActions, act );
5282 }
5284 // Offset spinbox
5285 {
5286 eact = create_adjustment_action(
5287 "OffsetAction",
5288 _("Grow/shrink by"), _("Grow/shrink by:"),
5289 _("The amount to grow (positive) or shrink (negative) the created fill path"),
5290 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
5291 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
5292 0, 0, 0,
5293 paintbucket_offset_changed, 1, 2);
5294 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
5296 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5297 }
5299 /* Auto Gap */
5300 {
5301 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5303 GList* items = 0;
5304 gint count = 0;
5305 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
5306 {
5307 GtkTreeIter iter;
5308 gtk_list_store_append( model, &iter );
5309 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5310 count++;
5311 }
5312 g_list_free( items );
5313 items = 0;
5314 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
5315 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
5316 ege_select_one_action_set_appearance( act2, "compact" );
5317 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
5318 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
5319 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
5320 g_object_set_data( holder, "autogap_action", act2 );
5321 }
5323 /* Reset */
5324 {
5325 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
5326 _("Defaults"),
5327 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
5328 GTK_STOCK_CLEAR );
5329 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
5330 gtk_action_group_add_action( mainActions, act );
5331 gtk_action_set_sensitive( act, TRUE );
5332 }
5334 }
5336 /*
5337 Local Variables:
5338 mode:c++
5339 c-file-style:"stroustrup"
5340 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
5341 indent-tabs-mode:nil
5342 fill-column:99
5343 End:
5344 */
5345 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :