c2c7ff8528566aeb7de8e569bc5c6923b5ee1c48
1 /** \file
2 * Controls bars for some of Inkscape's tools
3 * (for some tools, they are in their own files)
4 */
6 /*
7 *
8 * Authors:
9 * MenTaLguY <mental@rydia.net>
10 * Lauris Kaplinski <lauris@kaplinski.com>
11 * bulia byak <buliabyak@users.sf.net>
12 * Frank Felfe <innerspace@iname.com>
13 * John Cliff <simarilius@yahoo.com>
14 * David Turner <novalis@gnu.org>
15 * Josh Andler <scislac@scislac.com>
16 * Jon A. Cruz <jon@joncruz.org>
17 *
18 * Copyright (C) 2004 David Turner
19 * Copyright (C) 2003 MenTaLguY
20 * Copyright (C) 1999-2006 authors
21 * Copyright (C) 2001-2002 Ximian, Inc.
22 *
23 * Released under GNU GPL, read the file 'COPYING' for more information
24 */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <gtkmm.h>
31 #include <gtk/gtk.h>
32 #include <iostream>
33 #include <sstream>
35 #include "widgets/button.h"
36 #include "widgets/widget-sizes.h"
37 #include "widgets/spw-utilities.h"
38 #include "widgets/spinbutton-events.h"
39 #include "dialogs/text-edit.h"
41 #include "ui/widget/style-swatch.h"
43 #include "prefs-utils.h"
44 #include "verbs.h"
45 #include "sp-namedview.h"
46 #include "desktop.h"
47 #include "desktop-handles.h"
48 #include "xml/repr.h"
49 #include "xml/node-event-vector.h"
50 #include <glibmm/i18n.h>
51 #include "helper/unit-menu.h"
52 #include "helper/units.h"
54 #include "inkscape.h"
55 #include "conn-avoid-ref.h"
58 #include "select-toolbar.h"
59 #include "gradient-toolbar.h"
61 #include "connector-context.h"
62 #include "node-context.h"
63 #include "shape-editor.h"
64 #include "tweak-context.h"
65 #include "sp-rect.h"
66 #include "box3d.h"
67 #include "box3d-context.h"
68 #include "sp-star.h"
69 #include "sp-spiral.h"
70 #include "sp-ellipse.h"
71 #include "sp-text.h"
72 #include "sp-flowtext.h"
73 #include "style.h"
74 #include "selection.h"
75 #include "selection-chemistry.h"
76 #include "document-private.h"
77 #include "desktop-style.h"
78 #include "../libnrtype/font-lister.h"
79 #include "../connection-pool.h"
80 #include "../prefs-utils.h"
81 #include "../inkscape-stock.h"
82 #include "icon.h"
83 #include "graphlayout/graphlayout.h"
85 #include "mod360.h"
87 #include "toolbox.h"
89 #include "flood-context.h"
91 #include "ink-action.h"
92 #include "ege-adjustment-action.h"
93 #include "ege-output-action.h"
94 #include "ege-select-one-action.h"
95 #include "helper/unit-tracker.h"
97 using Inkscape::UnitTracker;
99 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
100 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
102 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
103 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
104 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
105 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
115 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
118 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
121 static struct {
122 gchar const *type_name;
123 gchar const *data_name;
124 sp_verb_t verb;
125 sp_verb_t doubleclick_verb;
126 } const tools[] = {
127 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
128 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
129 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
130 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
131 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
132 // { "SP3DBoxContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
133 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
134 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
135 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
136 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
137 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
138 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
139 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
140 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
141 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
142 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
143 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
144 { NULL, NULL, 0, 0 }
145 };
147 static struct {
148 gchar const *type_name;
149 gchar const *data_name;
150 GtkWidget *(*create_func)(SPDesktop *desktop);
151 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
152 gchar const *ui_name;
153 gint swatch_verb_id;
154 gchar const *swatch_tool;
155 gchar const *swatch_tip;
156 } const aux_toolboxes[] = {
157 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
158 SP_VERB_INVALID, 0, 0},
159 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
160 SP_VERB_INVALID, 0, 0},
161 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
162 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", _("Color/opacity used for color tweaking")},
163 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
164 SP_VERB_INVALID, 0, 0},
165 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
166 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
167 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
168 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
169 { "SP3DBoxContext", "3dbox_toolbox", 0, sp_3dbox_toolbox_prep, "3DBoxToolbar",
170 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
171 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
172 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
173 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
174 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
175 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
176 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
177 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
178 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
179 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
180 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
181 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
182 SP_VERB_INVALID, 0, 0},
183 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
184 SP_VERB_INVALID, 0, 0},
185 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
186 SP_VERB_INVALID, 0, 0},
187 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
188 SP_VERB_INVALID, 0, 0},
189 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
190 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
191 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
192 };
195 static gchar const * ui_descr =
196 "<ui>"
197 " <toolbar name='SelectToolbar'>"
198 " <toolitem action='EditSelectAll' />"
199 " <toolitem action='EditSelectAllInAllLayers' />"
200 " <toolitem action='EditDeselect' />"
201 " <separator />"
202 " <toolitem action='ObjectRotate90CCW' />"
203 " <toolitem action='ObjectRotate90' />"
204 " <toolitem action='ObjectFlipHorizontally' />"
205 " <toolitem action='ObjectFlipVertically' />"
206 " <separator />"
207 " <toolitem action='SelectionToBack' />"
208 " <toolitem action='SelectionLower' />"
209 " <toolitem action='SelectionRaise' />"
210 " <toolitem action='SelectionToFront' />"
211 " <separator />"
212 " <toolitem action='XAction' />"
213 " <toolitem action='YAction' />"
214 " <toolitem action='WidthAction' />"
215 " <toolitem action='LockAction' />"
216 " <toolitem action='HeightAction' />"
217 " <toolitem action='UnitsAction' />"
218 " <separator />"
219 " <toolitem action='transform_affect_label' />"
220 " <toolitem action='transform_stroke' />"
221 " <toolitem action='transform_corners' />"
222 " <toolitem action='transform_gradient' />"
223 " <toolitem action='transform_pattern' />"
224 " </toolbar>"
226 " <toolbar name='NodeToolbar'>"
227 " <toolitem action='NodeInsertAction' />"
228 " <toolitem action='NodeDeleteAction' />"
229 " <separator />"
230 " <toolitem action='NodeJoinAction' />"
231 " <toolitem action='NodeJoinSegmentAction' />"
232 " <toolitem action='NodeDeleteSegmentAction' />"
233 " <toolitem action='NodeBreakAction' />"
234 " <separator />"
235 " <toolitem action='NodeCuspAction' />"
236 " <toolitem action='NodeSmoothAction' />"
237 " <toolitem action='NodeSymmetricAction' />"
238 " <separator />"
239 " <toolitem action='NodeLineAction' />"
240 " <toolitem action='NodeCurveAction' />"
241 " <separator />"
242 " <toolitem action='ObjectToPath' />"
243 " <toolitem action='StrokeToPath' />"
244 " <separator />"
245 " <toolitem action='NodesShowHandlesAction' />"
246 " <separator />"
247 " <toolitem action='EditNextLPEParameterAction' />"
248 " <separator />"
249 " <toolitem action='NodeXAction' />"
250 " <toolitem action='NodeYAction' />"
251 " </toolbar>"
253 " <toolbar name='TweakToolbar'>"
254 " <toolitem action='TweakWidthAction' />"
255 " <separator />"
256 " <toolitem action='TweakForceAction' />"
257 " <toolitem action='TweakPressureAction' />"
258 " <separator />"
259 " <toolitem action='TweakModeAction' />"
260 " <separator />"
261 " <toolitem action='TweakFidelityAction' />"
262 " <separator />"
263 " <toolitem action='TweakChannelsLabel' />"
264 " <toolitem action='TweakDoH' />"
265 " <toolitem action='TweakDoS' />"
266 " <toolitem action='TweakDoL' />"
267 " <toolitem action='TweakDoO' />"
268 " </toolbar>"
270 " <toolbar name='ZoomToolbar'>"
271 " <toolitem action='ZoomIn' />"
272 " <toolitem action='ZoomOut' />"
273 " <separator />"
274 " <toolitem action='Zoom1:0' />"
275 " <toolitem action='Zoom1:2' />"
276 " <toolitem action='Zoom2:1' />"
277 " <separator />"
278 " <toolitem action='ZoomSelection' />"
279 " <toolitem action='ZoomDrawing' />"
280 " <toolitem action='ZoomPage' />"
281 " <toolitem action='ZoomPageWidth' />"
282 " <separator />"
283 " <toolitem action='ZoomPrev' />"
284 " <toolitem action='ZoomNext' />"
285 " </toolbar>"
287 " <toolbar name='StarToolbar'>"
288 " <separator />"
289 " <toolitem action='StarStateAction' />"
290 " <separator />"
291 " <toolitem action='FlatAction' />"
292 " <separator />"
293 " <toolitem action='MagnitudeAction' />"
294 " <toolitem action='SpokeAction' />"
295 " <toolitem action='RoundednessAction' />"
296 " <toolitem action='RandomizationAction' />"
297 " <separator />"
298 " <toolitem action='StarResetAction' />"
299 " </toolbar>"
301 " <toolbar name='RectToolbar'>"
302 " <toolitem action='RectStateAction' />"
303 " <toolitem action='RectWidthAction' />"
304 " <toolitem action='RectHeightAction' />"
305 " <toolitem action='RadiusXAction' />"
306 " <toolitem action='RadiusYAction' />"
307 " <toolitem action='RectUnitsAction' />"
308 " <separator />"
309 " <toolitem action='RectResetAction' />"
310 " </toolbar>"
312 " <toolbar name='3DBoxToolbar'>"
313 " <toolitem action='3DBoxPosAngleXAction' />"
314 " <toolitem action='3DBoxVPXAction' />"
315 " <separator />"
316 " <toolitem action='3DBoxPosAngleYAction' />"
317 " <toolitem action='3DBoxVPYAction' />"
318 " <separator />"
319 " <toolitem action='3DBoxPosAngleZAction' />"
320 " <toolitem action='3DBoxVPZAction' />"
321 " <separator />"
322 " </toolbar>"
324 " <toolbar name='SpiralToolbar'>"
325 " <toolitem action='SpiralStateAction' />"
326 " <toolitem action='SpiralRevolutionAction' />"
327 " <toolitem action='SpiralExpansionAction' />"
328 " <toolitem action='SpiralT0Action' />"
329 " <separator />"
330 " <toolitem action='SpiralResetAction' />"
331 " </toolbar>"
333 " <toolbar name='PenToolbar'>"
334 " </toolbar>"
336 " <toolbar name='PencilToolbar'>"
337 " </toolbar>"
339 " <toolbar name='CalligraphyToolbar'>"
340 " <separator />"
341 " <toolitem action='CalligraphyWidthAction' />"
342 " <toolitem action='PressureAction' />"
343 " <toolitem action='TraceAction' />"
344 " <toolitem action='ThinningAction' />"
345 " <separator />"
346 " <toolitem action='AngleAction' />"
347 " <toolitem action='TiltAction' />"
348 " <toolitem action='FixationAction' />"
349 " <separator />"
350 " <toolitem action='CapRoundingAction' />"
351 " <separator />"
352 " <toolitem action='TremorAction' />"
353 " <toolitem action='WiggleAction' />"
354 " <toolitem action='MassAction' />"
355 " <separator />"
356 " <toolitem action='CalligraphyResetAction' />"
357 " </toolbar>"
359 " <toolbar name='ArcToolbar'>"
360 " <toolitem action='ArcStateAction' />"
361 " <separator />"
362 " <toolitem action='ArcStartAction' />"
363 " <toolitem action='ArcEndAction' />"
364 " <separator />"
365 " <toolitem action='ArcOpenAction' />"
366 " <separator />"
367 " <toolitem action='ArcResetAction' />"
368 " <separator />"
369 " </toolbar>"
371 " <toolbar name='PaintbucketToolbar'>"
372 " <toolitem action='ChannelsAction' />"
373 " <separator />"
374 " <toolitem action='ThresholdAction' />"
375 " <separator />"
376 " <toolitem action='OffsetAction' />"
377 " <toolitem action='PaintbucketUnitsAction' />"
378 " <separator />"
379 " <toolitem action='AutoGapAction' />"
380 " <separator />"
381 " <toolitem action='PaintbucketResetAction' />"
382 " </toolbar>"
384 " <toolbar name='DropperToolbar'>"
385 " <toolitem action='DropperPickAlphaAction' />"
386 " <toolitem action='DropperSetAlphaAction' />"
387 " </toolbar>"
389 " <toolbar name='ConnectorToolbar'>"
390 " <toolitem action='ConnectorAvoidAction' />"
391 " <toolitem action='ConnectorIgnoreAction' />"
392 " <toolitem action='ConnectorSpacingAction' />"
393 " <toolitem action='ConnectorGraphAction' />"
394 " <toolitem action='ConnectorLengthAction' />"
395 " <toolitem action='ConnectorDirectedAction' />"
396 " <toolitem action='ConnectorOverlapAction' />"
397 " </toolbar>"
399 "</ui>"
400 ;
402 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
404 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
406 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
407 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
409 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
410 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
412 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
413 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
415 /* Global text entry widgets necessary for update */
416 /* GtkWidget *dropper_rgb_entry,
417 *dropper_opacity_entry ; */
418 // should be made a private member once this is converted to class
420 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
421 connection->disconnect();
422 delete connection;
423 }
425 static void purge_repr_listener( GObject* obj, GObject* tbl )
426 {
427 (void)obj;
428 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
429 if (oldrepr) { // remove old listener
430 sp_repr_remove_listener_by_data(oldrepr, tbl);
431 Inkscape::GC::release(oldrepr);
432 oldrepr = 0;
433 g_object_set_data( tbl, "repr", NULL );
434 }
435 }
437 GtkWidget *
438 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
439 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
440 Inkscape::UI::View::View *view, GtkTooltips *tt)
441 {
442 SPAction *action = verb->get_action(view);
443 if (!action) return NULL;
445 SPAction *doubleclick_action;
446 if (doubleclick_verb)
447 doubleclick_action = doubleclick_verb->get_action(view);
448 else
449 doubleclick_action = NULL;
451 /* fixme: Handle sensitive/unsensitive */
452 /* fixme: Implement sp_button_new_from_action */
453 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
454 gtk_widget_show(b);
455 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
457 return b;
458 }
460 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
461 Inkscape::UI::View::View *view, GtkTooltips *tt)
462 {
463 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
464 }
466 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
467 Inkscape::UI::View::View *view, GtkTooltips *tt)
468 {
469 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
470 }
473 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
474 {
475 SPAction* targetAction = SP_ACTION(user_data);
476 if ( targetAction ) {
477 sp_action_perform( targetAction, NULL );
478 }
479 }
481 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
482 {
483 if ( data ) {
484 GtkAction* act = GTK_ACTION(data);
485 gtk_action_set_sensitive( act, sensitive );
486 }
487 }
489 static SPActionEventVector action_event_vector = {
490 {NULL},
491 NULL,
492 NULL,
493 sp_action_action_set_sensitive,
494 NULL,
495 NULL
496 };
498 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
499 {
500 GtkAction* act = 0;
502 SPAction* targetAction = verb->get_action(view);
503 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
504 act = GTK_ACTION(inky);
505 gtk_action_set_sensitive( act, targetAction->sensitive );
507 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
509 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
510 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
512 return act;
513 }
515 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
516 {
517 Inkscape::UI::View::View *view = desktop;
518 gint verbsToUse[] = {
519 // disabled until we have icons for them:
520 //find
521 //SP_VERB_EDIT_TILE,
522 //SP_VERB_EDIT_UNTILE,
523 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
524 SP_VERB_DIALOG_DISPLAY,
525 SP_VERB_DIALOG_FILL_STROKE,
526 SP_VERB_DIALOG_NAMEDVIEW,
527 SP_VERB_DIALOG_TEXT,
528 SP_VERB_DIALOG_XML_EDITOR,
529 SP_VERB_EDIT_CLONE,
530 SP_VERB_EDIT_COPY,
531 SP_VERB_EDIT_CUT,
532 SP_VERB_EDIT_DUPLICATE,
533 SP_VERB_EDIT_PASTE,
534 SP_VERB_EDIT_REDO,
535 SP_VERB_EDIT_UNDO,
536 SP_VERB_EDIT_UNLINK_CLONE,
537 SP_VERB_FILE_EXPORT,
538 SP_VERB_FILE_IMPORT,
539 SP_VERB_FILE_NEW,
540 SP_VERB_FILE_OPEN,
541 SP_VERB_FILE_PRINT,
542 SP_VERB_FILE_SAVE,
543 SP_VERB_OBJECT_TO_CURVE,
544 SP_VERB_SELECTION_GROUP,
545 SP_VERB_SELECTION_OUTLINE,
546 SP_VERB_SELECTION_UNGROUP,
547 SP_VERB_ZOOM_1_1,
548 SP_VERB_ZOOM_1_2,
549 SP_VERB_ZOOM_2_1,
550 SP_VERB_ZOOM_DRAWING,
551 SP_VERB_ZOOM_IN,
552 SP_VERB_ZOOM_NEXT,
553 SP_VERB_ZOOM_OUT,
554 SP_VERB_ZOOM_PAGE,
555 SP_VERB_ZOOM_PAGE_WIDTH,
556 SP_VERB_ZOOM_PREV,
557 SP_VERB_ZOOM_SELECTION,
558 };
560 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
561 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
563 static std::map<SPDesktop*, GtkActionGroup*> groups;
564 GtkActionGroup* mainActions = 0;
565 if ( groups.find(desktop) != groups.end() ) {
566 mainActions = groups[desktop];
567 }
569 if ( !mainActions ) {
570 mainActions = gtk_action_group_new("main");
571 groups[desktop] = mainActions;
572 }
574 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
575 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
576 if ( verb ) {
577 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
578 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
579 gtk_action_group_add_action( mainActions, act );
580 }
581 }
582 }
584 return mainActions;
585 }
588 GtkWidget *
589 sp_tool_toolbox_new()
590 {
591 GtkTooltips *tt = gtk_tooltips_new();
592 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
594 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
595 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
597 gtk_widget_set_sensitive(tb, FALSE);
599 GtkWidget *hb = gtk_handle_box_new();
600 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
601 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
602 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
604 gtk_container_add(GTK_CONTAINER(hb), tb);
605 gtk_widget_show(GTK_WIDGET(tb));
607 sigc::connection* conn = new sigc::connection;
608 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
610 return hb;
611 }
613 static void
614 aux_toolbox_attached(GtkHandleBox */*toolbox*/, GtkWidget *child)
615 {
616 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
617 gtk_widget_queue_resize(child);
618 }
620 static void
621 aux_toolbox_detached(GtkHandleBox */*toolbox*/, GtkWidget *child)
622 {
623 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
624 gtk_widget_queue_resize(child);
625 }
627 GtkWidget *
628 sp_aux_toolbox_new()
629 {
630 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
632 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
633 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
634 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
635 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
636 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
638 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
639 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
641 gtk_widget_set_sensitive(tb, FALSE);
643 GtkWidget *hb = gtk_handle_box_new();
644 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
645 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
646 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
648 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
649 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
651 gtk_container_add(GTK_CONTAINER(hb), tb);
652 gtk_widget_show(GTK_WIDGET(tb));
654 sigc::connection* conn = new sigc::connection;
655 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
657 return hb;
658 }
660 //####################################
661 //# Commands Bar
662 //####################################
664 GtkWidget *
665 sp_commands_toolbox_new()
666 {
667 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
669 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
670 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
671 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
672 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
673 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
675 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
676 gtk_widget_set_sensitive(tb, FALSE);
678 GtkWidget *hb = gtk_handle_box_new();
679 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
680 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
681 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
683 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
684 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
686 gtk_container_add(GTK_CONTAINER(hb), tb);
687 gtk_widget_show(GTK_WIDGET(tb));
689 sigc::connection* conn = new sigc::connection;
690 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
692 return hb;
693 }
695 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
696 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
697 gchar const *path, gchar const *data, gdouble def,
698 GtkWidget *focusTarget,
699 GtkWidget *us,
700 GObject *dataKludge,
701 gboolean altx, gchar const *altx_mark,
702 gdouble lower, gdouble upper, gdouble step, gdouble page,
703 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
704 void (*callback)(GtkAdjustment *, GObject *),
705 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
706 {
707 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
708 lower, upper, step, page, page ) );
709 if (us) {
710 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
711 }
713 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
715 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
716 if ( shortLabel ) {
717 g_object_set( act, "short_label", shortLabel, NULL );
718 }
720 if ( (descrCount > 0) && descrLabels && descrValues ) {
721 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
722 }
724 if ( focusTarget ) {
725 ege_adjustment_action_set_focuswidget( act, focusTarget );
726 }
728 if ( altx && altx_mark ) {
729 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
730 }
732 if ( dataKludge ) {
733 g_object_set_data( dataKludge, data, adj );
734 }
736 // Using a cast just to make sure we pass in the right kind of function pointer
737 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
739 return act;
740 }
743 //####################################
744 //# node editing callbacks
745 //####################################
747 /**
748 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
749 */
750 static ShapeEditor *get_current_shape_editor()
751 {
752 if (!SP_ACTIVE_DESKTOP) {
753 return NULL;
754 }
756 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
758 if (!SP_IS_NODE_CONTEXT(event_context)) {
759 return NULL;
760 }
762 return SP_NODE_CONTEXT(event_context)->shape_editor;
763 }
766 void
767 sp_node_path_edit_add(void)
768 {
769 ShapeEditor *shape_editor = get_current_shape_editor();
770 if (shape_editor) shape_editor->add_node();
771 }
773 void
774 sp_node_path_edit_delete(void)
775 {
776 ShapeEditor *shape_editor = get_current_shape_editor();
777 if (shape_editor) shape_editor->delete_nodes();
778 }
780 void
781 sp_node_path_edit_delete_segment(void)
782 {
783 ShapeEditor *shape_editor = get_current_shape_editor();
784 if (shape_editor) shape_editor->delete_segment();
785 }
787 void
788 sp_node_path_edit_break(void)
789 {
790 ShapeEditor *shape_editor = get_current_shape_editor();
791 if (shape_editor) shape_editor->break_at_nodes();
792 }
794 void
795 sp_node_path_edit_join(void)
796 {
797 ShapeEditor *shape_editor = get_current_shape_editor();
798 if (shape_editor) shape_editor->join_nodes();
799 }
801 void
802 sp_node_path_edit_join_segment(void)
803 {
804 ShapeEditor *shape_editor = get_current_shape_editor();
805 if (shape_editor) shape_editor->join_segments();
806 }
808 void
809 sp_node_path_edit_toline(void)
810 {
811 ShapeEditor *shape_editor = get_current_shape_editor();
812 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
813 }
815 void
816 sp_node_path_edit_tocurve(void)
817 {
818 ShapeEditor *shape_editor = get_current_shape_editor();
819 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
820 }
822 void
823 sp_node_path_edit_cusp(void)
824 {
825 ShapeEditor *shape_editor = get_current_shape_editor();
826 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
827 }
829 void
830 sp_node_path_edit_smooth(void)
831 {
832 ShapeEditor *shape_editor = get_current_shape_editor();
833 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
834 }
836 void
837 sp_node_path_edit_symmetrical(void)
838 {
839 ShapeEditor *shape_editor = get_current_shape_editor();
840 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
841 }
843 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
844 bool show = gtk_toggle_action_get_active( act );
845 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
846 ShapeEditor *shape_editor = get_current_shape_editor();
847 if (shape_editor) shape_editor->show_handles(show);
848 }
850 void
851 sp_node_path_edit_nextLPEparam (GtkAction *act, gpointer data) {
852 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
853 }
855 /* is called when the node selection is modified */
856 static void
857 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
858 {
859 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
860 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
861 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
862 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
864 // quit if run by the attr_changed listener
865 if (g_object_get_data( tbl, "freeze" )) {
866 return;
867 }
869 // in turn, prevent listener from responding
870 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
872 ShapeEditor *shape_editor = get_current_shape_editor();
873 if (shape_editor && shape_editor->has_nodepath()) {
874 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
875 int n_selected = 0;
876 if (nodepath) {
877 n_selected = nodepath->numSelected();
878 }
880 if (n_selected == 0) {
881 gtk_action_set_sensitive(xact, FALSE);
882 gtk_action_set_sensitive(yact, FALSE);
883 } else {
884 gtk_action_set_sensitive(xact, TRUE);
885 gtk_action_set_sensitive(yact, TRUE);
886 NR::Coord oldx = gtk_adjustment_get_value(xadj);
887 NR::Coord oldy = gtk_adjustment_get_value(xadj);
889 if (n_selected == 1) {
890 NR::Point sel_node = nodepath->singleSelectedCoords();
891 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
892 gtk_adjustment_set_value(xadj, sel_node[NR::X]);
893 gtk_adjustment_set_value(yadj, sel_node[NR::Y]);
894 }
895 } else {
896 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
897 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
898 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
899 /* Note: Currently x and y will always have a value, even if the coordinates of the
900 selected nodes don't coincide (in this case we use the coordinates of the center
901 of the bounding box). So the entries are never set to zero. */
902 gtk_adjustment_set_value(xadj, x ? (*x) : 0.0); // FIXME: Maybe we should clear the entry
903 gtk_adjustment_set_value(yadj, y ? (*y) : 0.0); // fields, not set them to zero.
904 }
905 }
906 }
907 } else {
908 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
909 gtk_action_set_sensitive(xact, FALSE);
910 gtk_action_set_sensitive(yact, FALSE);
911 }
913 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
914 }
916 static void
917 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
918 {
919 // quit if run by the attr_changed listener
920 if (g_object_get_data( tbl, "freeze" )) {
921 return;
922 }
924 // in turn, prevent listener from responding
925 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
927 ShapeEditor *shape_editor = get_current_shape_editor();
928 if (shape_editor && shape_editor->has_nodepath()) {
929 if (!strcmp(value_name, "x")) {
930 sp_node_selected_move_absolute(shape_editor->get_nodepath(), gtk_adjustment_get_value(adj), NR::X);
931 }
932 if (!strcmp(value_name, "y")) {
933 sp_node_selected_move_absolute(shape_editor->get_nodepath(), gtk_adjustment_get_value(adj), NR::Y);
934 }
935 }
937 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
938 }
940 static void
941 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
942 {
943 sp_node_path_value_changed(adj, tbl, "x");
944 }
946 static void
947 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
948 {
949 sp_node_path_value_changed(adj, tbl, "y");
950 }
952 //################################
953 //## Node Editing Toolbox ##
954 //################################
956 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
957 {
958 {
959 InkAction* inky = ink_action_new( "NodeInsertAction",
960 _("Insert node"),
961 _("Insert new nodes into selected segments"),
962 "node_insert",
963 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
964 g_object_set( inky, "short_label", _("Insert"), NULL );
965 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
966 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
967 }
969 {
970 InkAction* inky = ink_action_new( "NodeDeleteAction",
971 _("Delete node"),
972 _("Delete selected nodes"),
973 "node_delete",
974 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
975 g_object_set( inky, "short_label", _("Delete"), NULL );
976 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
977 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
978 }
980 {
981 InkAction* inky = ink_action_new( "NodeJoinAction",
982 _("Join endnodes"),
983 _("Join selected endnodes"),
984 "node_join",
985 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
986 g_object_set( inky, "short_label", _("Join"), NULL );
987 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
988 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
989 }
991 {
992 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
993 _("Join Segment"),
994 _("Join selected endnodes with a new segment"),
995 "node_join_segment",
996 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
997 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
998 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
999 }
1001 {
1002 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1003 _("Delete Segment"),
1004 _("Split path between two non-endpoint nodes"),
1005 "node_delete_segment",
1006 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1007 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1008 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1009 }
1011 {
1012 InkAction* inky = ink_action_new( "NodeBreakAction",
1013 _("Node Break"),
1014 _("Break path at selected nodes"),
1015 "node_break",
1016 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1017 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1018 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1019 }
1021 {
1022 InkAction* inky = ink_action_new( "NodeCuspAction",
1023 _("Node Cusp"),
1024 _("Make selected nodes corner"),
1025 "node_cusp",
1026 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1027 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1028 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1029 }
1031 {
1032 InkAction* inky = ink_action_new( "NodeSmoothAction",
1033 _("Node Smooth"),
1034 _("Make selected nodes smooth"),
1035 "node_smooth",
1036 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1037 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1038 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1039 }
1041 {
1042 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1043 _("Node Symmetric"),
1044 _("Make selected nodes symmetric"),
1045 "node_symmetric",
1046 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1047 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1048 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1049 }
1051 {
1052 InkAction* inky = ink_action_new( "NodeLineAction",
1053 _("Node Line"),
1054 _("Make selected segments lines"),
1055 "node_line",
1056 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1057 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1058 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1059 }
1061 {
1062 InkAction* inky = ink_action_new( "NodeCurveAction",
1063 _("Node Curve"),
1064 _("Make selected segments curves"),
1065 "node_curve",
1066 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1067 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1068 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1069 }
1071 {
1072 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1073 _("Show Handles"),
1074 _("Show the Bezier handles of selected nodes"),
1075 "nodes_show_handles",
1076 Inkscape::ICON_SIZE_DECORATION );
1077 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1078 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1079 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1080 }
1082 {
1083 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1084 _("Next Path Effect Parameter"),
1085 _("Show next Path Effect parameter for editing"),
1086 "edit_next_parameter",
1087 Inkscape::ICON_SIZE_DECORATION );
1088 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1089 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1090 }
1092 /* X coord of selected node(s) */
1093 {
1094 EgeAdjustmentAction* eact = 0;
1095 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1096 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1097 eact = create_adjustment_action( "NodeXAction",
1098 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1099 "tools.nodes", "Xcoord", 0,
1100 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1101 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1102 labels, values, G_N_ELEMENTS(labels),
1103 sp_node_path_x_value_changed );
1104 g_object_set_data( holder, "nodes_x_action", eact );
1105 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1106 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1107 }
1109 /* Y coord of selected node(s) */
1110 {
1111 EgeAdjustmentAction* eact = 0;
1112 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1113 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1114 eact = create_adjustment_action( "NodeYAction",
1115 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1116 "tools.nodes", "Ycoord", 0,
1117 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1118 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1119 labels, values, G_N_ELEMENTS(labels),
1120 sp_node_path_y_value_changed );
1121 g_object_set_data( holder, "nodes_y_action", eact );
1122 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1123 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1124 }
1126 sigc::connection *connection = new sigc::connection (
1127 desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(sp_node_toolbox_coord_changed), (GObject *)holder))
1128 );
1130 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1131 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1132 } // end of sp_node_toolbox_prep()
1135 //########################
1136 //## Zoom Toolbox ##
1137 //########################
1139 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1140 {
1141 // no custom GtkAction setup needed
1142 } // end of sp_zoom_toolbox_prep()
1144 void
1145 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1146 {
1147 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")));
1148 }
1151 void
1152 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1153 {
1154 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")));
1155 }
1157 void
1158 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1159 {
1160 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")));
1161 }
1163 static void
1164 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1165 {
1166 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1167 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1169 if (old_desktop) {
1170 GList *children, *iter;
1172 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1173 for ( iter = children ; iter ; iter = iter->next ) {
1174 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1175 }
1176 g_list_free(children);
1177 }
1179 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1181 if (desktop) {
1182 gtk_widget_set_sensitive(toolbox, TRUE);
1183 setup_func(toolbox, desktop);
1184 update_func(desktop, desktop->event_context, toolbox);
1185 *conn = desktop->connectEventContextChanged
1186 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1187 } else {
1188 gtk_widget_set_sensitive(toolbox, FALSE);
1189 }
1191 } // end of toolbox_set_desktop()
1194 static void
1195 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1196 {
1197 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
1198 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
1199 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
1200 // "toolbox.tools" was not set. Fallback to older value
1201 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
1203 // Copy the setting forwards
1204 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
1205 }
1206 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1208 for (int i = 0 ; tools[i].type_name ; i++ ) {
1209 GtkWidget *button =
1210 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
1211 SP_BUTTON_TYPE_TOGGLE,
1212 Inkscape::Verb::get(tools[i].verb),
1213 Inkscape::Verb::get(tools[i].doubleclick_verb),
1214 desktop,
1215 tooltips );
1217 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1218 (gpointer)button );
1219 }
1220 }
1223 static void
1224 update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
1225 {
1226 gchar const *const tname = ( eventcontext
1227 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1228 : NULL );
1229 for (int i = 0 ; tools[i].type_name ; i++ ) {
1230 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1231 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1232 }
1233 }
1235 static void
1236 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1237 {
1238 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1239 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1240 GtkUIManager* mgr = gtk_ui_manager_new();
1241 GError* errVal = 0;
1242 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1243 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1245 std::map<std::string, GtkWidget*> dataHolders;
1247 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1248 if ( aux_toolboxes[i].prep_func ) {
1249 // converted to GtkActions and UIManager
1251 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1252 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1253 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1254 dataHolders[aux_toolboxes[i].type_name] = kludge;
1255 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1256 } else {
1258 GtkWidget *sub_toolbox = 0;
1259 if (aux_toolboxes[i].create_func == NULL)
1260 sub_toolbox = sp_empty_toolbox_new(desktop);
1261 else {
1262 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1263 }
1265 gtk_size_group_add_widget( grouper, sub_toolbox );
1267 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1268 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1270 }
1271 }
1273 // Second pass to create toolbars *after* all GtkActions are created
1274 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1275 if ( aux_toolboxes[i].prep_func ) {
1276 // converted to GtkActions and UIManager
1278 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1280 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1281 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1283 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1284 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1285 g_free( tmp );
1286 tmp = 0;
1288 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1289 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1290 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1291 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1292 }
1293 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1296 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1298 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1299 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1300 swatch->setDesktop( desktop );
1301 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1302 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1303 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1304 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 );
1305 }
1307 gtk_widget_show_all( holder );
1308 sp_set_font_size_smaller( holder );
1310 gtk_size_group_add_widget( grouper, holder );
1312 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1313 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1314 }
1315 }
1317 g_object_unref( G_OBJECT(grouper) );
1318 }
1320 static void
1321 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1322 {
1323 gchar const *tname = ( eventcontext
1324 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1325 : NULL );
1326 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1327 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1328 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1329 gtk_widget_show_all(sub_toolbox);
1330 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1331 } else {
1332 gtk_widget_hide(sub_toolbox);
1333 }
1334 }
1335 }
1337 static void
1338 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1339 {
1340 gchar const * descr =
1341 "<ui>"
1342 " <toolbar name='CommandsToolbar'>"
1343 " <toolitem action='FileNew' />"
1344 " <toolitem action='FileOpen' />"
1345 " <toolitem action='FileSave' />"
1346 " <toolitem action='FilePrint' />"
1347 " <separator />"
1348 " <toolitem action='FileImport' />"
1349 " <toolitem action='FileExport' />"
1350 " <separator />"
1351 " <toolitem action='EditUndo' />"
1352 " <toolitem action='EditRedo' />"
1353 " <separator />"
1354 " <toolitem action='EditCopy' />"
1355 " <toolitem action='EditCut' />"
1356 " <toolitem action='EditPaste' />"
1357 " <separator />"
1358 " <toolitem action='ZoomSelection' />"
1359 " <toolitem action='ZoomDrawing' />"
1360 " <toolitem action='ZoomPage' />"
1361 " <separator />"
1362 " <toolitem action='EditDuplicate' />"
1363 " <toolitem action='EditClone' />"
1364 " <toolitem action='EditUnlinkClone' />"
1365 " <separator />"
1366 " <toolitem action='SelectionGroup' />"
1367 " <toolitem action='SelectionUnGroup' />"
1368 " <separator />"
1369 " <toolitem action='DialogFillStroke' />"
1370 " <toolitem action='DialogText' />"
1371 " <toolitem action='DialogXMLEditor' />"
1372 " <toolitem action='DialogAlignDistribute' />"
1373 " <separator />"
1374 " <toolitem action='DialogPreferences' />"
1375 " <toolitem action='DialogDocumentProperties' />"
1376 " </toolbar>"
1377 "</ui>";
1378 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1381 GtkUIManager* mgr = gtk_ui_manager_new();
1382 GError* errVal = 0;
1384 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1385 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1387 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1388 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1389 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1390 }
1391 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1392 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1393 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1396 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1397 }
1399 static void
1400 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1401 {
1402 }
1404 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1405 {
1406 gtk_widget_show(toolbox_toplevel);
1407 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1409 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1410 if (!shown_toolbox) {
1411 return;
1412 }
1413 gtk_widget_show(toolbox);
1415 // need to show the spacer, or the padding will be off
1416 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1417 gtk_widget_show(spacer);
1419 gtk_widget_show_all(shown_toolbox);
1420 }
1422 void
1423 aux_toolbox_space(GtkWidget *tb, gint space)
1424 {
1425 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1426 }
1428 static GtkWidget *
1429 sp_empty_toolbox_new(SPDesktop *desktop)
1430 {
1431 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1432 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1433 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1435 gtk_widget_show_all(tbl);
1436 sp_set_font_size_smaller (tbl);
1438 return tbl;
1439 }
1441 // helper UI functions
1443 GtkWidget *
1444 sp_tb_spinbutton(
1445 gchar *label, gchar const *tooltip,
1446 gchar const *path, gchar const *data, gdouble def,
1447 GtkWidget *us,
1448 GtkWidget *tbl,
1449 gboolean altx, gchar const *altx_mark,
1450 gdouble lower, gdouble upper, gdouble step, gdouble page,
1451 void (*callback)(GtkAdjustment *, GtkWidget *),
1452 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1453 {
1454 GtkTooltips *tt = gtk_tooltips_new();
1456 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1458 GtkWidget *l = gtk_label_new(label);
1459 gtk_widget_show(l);
1460 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1461 gtk_container_add(GTK_CONTAINER(hb), l);
1463 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1464 lower, upper, step, page, page);
1465 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1466 if (us)
1467 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1469 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1470 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1471 if (altx)
1472 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1473 gtk_widget_set_size_request(sb,
1474 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1475 AUX_SPINBUTTON_HEIGHT);
1476 gtk_widget_show(sb);
1477 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1478 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1479 gtk_container_add(GTK_CONTAINER(hb), sb);
1480 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1482 return hb;
1483 }
1485 #define MODE_LABEL_WIDTH 70
1487 //########################
1488 //## Star ##
1489 //########################
1491 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1492 {
1493 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1495 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1496 // do not remember prefs if this call is initiated by an undo change, because undoing object
1497 // creation sets bogus values to its attributes before it is deleted
1498 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1499 }
1501 // quit if run by the attr_changed listener
1502 if (g_object_get_data( dataKludge, "freeze" )) {
1503 return;
1504 }
1506 // in turn, prevent listener from responding
1507 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1509 bool modmade = false;
1511 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1512 GSList const *items = selection->itemList();
1513 for (; items != NULL; items = items->next) {
1514 if (SP_IS_STAR((SPItem *) items->data)) {
1515 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1516 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1517 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1518 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1519 + M_PI / (gint)adj->value));
1520 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1521 modmade = true;
1522 }
1523 }
1524 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1525 _("Star: Change number of corners"));
1527 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1528 }
1530 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1531 {
1532 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1534 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1535 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1536 }
1538 // quit if run by the attr_changed listener
1539 if (g_object_get_data( dataKludge, "freeze" )) {
1540 return;
1541 }
1543 // in turn, prevent listener from responding
1544 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1546 bool modmade = false;
1547 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1548 GSList const *items = selection->itemList();
1549 for (; items != NULL; items = items->next) {
1550 if (SP_IS_STAR((SPItem *) items->data)) {
1551 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1553 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1554 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1555 if (r2 < r1) {
1556 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1557 } else {
1558 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1559 }
1561 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1562 modmade = true;
1563 }
1564 }
1566 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1567 _("Star: Change spoke ratio"));
1569 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1570 }
1572 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1573 {
1574 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1575 bool flat = ege_select_one_action_get_active( act ) == 0;
1577 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1578 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1579 flat ? "true" : "false" );
1580 }
1582 // quit if run by the attr_changed listener
1583 if (g_object_get_data( dataKludge, "freeze" )) {
1584 return;
1585 }
1587 // in turn, prevent listener from responding
1588 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1590 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1591 GSList const *items = selection->itemList();
1592 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1593 bool modmade = false;
1595 if ( prop_action ) {
1596 gtk_action_set_sensitive( prop_action, !flat );
1597 }
1599 for (; items != NULL; items = items->next) {
1600 if (SP_IS_STAR((SPItem *) items->data)) {
1601 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1602 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1603 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1604 modmade = true;
1605 }
1606 }
1608 if (modmade) {
1609 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1610 flat ? _("Make polygon") : _("Make star"));
1611 }
1613 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1614 }
1616 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1617 {
1618 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1620 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1621 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1622 }
1624 // quit if run by the attr_changed listener
1625 if (g_object_get_data( dataKludge, "freeze" )) {
1626 return;
1627 }
1629 // in turn, prevent listener from responding
1630 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1632 bool modmade = false;
1634 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1635 GSList const *items = selection->itemList();
1636 for (; items != NULL; items = items->next) {
1637 if (SP_IS_STAR((SPItem *) items->data)) {
1638 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1639 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1640 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1641 modmade = true;
1642 }
1643 }
1644 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1645 _("Star: Change rounding"));
1647 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1648 }
1650 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1651 {
1652 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1654 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1655 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1656 }
1658 // quit if run by the attr_changed listener
1659 if (g_object_get_data( dataKludge, "freeze" )) {
1660 return;
1661 }
1663 // in turn, prevent listener from responding
1664 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1666 bool modmade = false;
1668 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1669 GSList const *items = selection->itemList();
1670 for (; items != NULL; items = items->next) {
1671 if (SP_IS_STAR((SPItem *) items->data)) {
1672 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1673 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1674 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1675 modmade = true;
1676 }
1677 }
1678 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1679 _("Star: Change randomization"));
1681 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1682 }
1685 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1686 gchar const */*old_value*/, gchar const */*new_value*/,
1687 bool /*is_interactive*/, gpointer data)
1688 {
1689 GtkWidget *tbl = GTK_WIDGET(data);
1691 // quit if run by the _changed callbacks
1692 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1693 return;
1694 }
1696 // in turn, prevent callbacks from responding
1697 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1699 GtkAdjustment *adj = 0;
1701 if (!strcmp(name, "inkscape:randomized")) {
1702 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1703 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1704 } else if (!strcmp(name, "inkscape:rounded")) {
1705 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1706 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1707 } else if (!strcmp(name, "inkscape:flatsided")) {
1708 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1709 char const *flatsides = repr->attribute("inkscape:flatsided");
1710 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1711 if ( flatsides && !strcmp(flatsides,"false") ) {
1712 ege_select_one_action_set_active( flat_action, 1 );
1713 gtk_action_set_sensitive( prop_action, TRUE );
1714 } else {
1715 ege_select_one_action_set_active( flat_action, 0 );
1716 gtk_action_set_sensitive( prop_action, FALSE );
1717 }
1718 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1719 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1720 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1721 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1722 if (r2 < r1) {
1723 gtk_adjustment_set_value(adj, r2/r1);
1724 } else {
1725 gtk_adjustment_set_value(adj, r1/r2);
1726 }
1727 } else if (!strcmp(name, "sodipodi:sides")) {
1728 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1729 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1730 }
1732 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1733 }
1736 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1737 {
1738 NULL, /* child_added */
1739 NULL, /* child_removed */
1740 star_tb_event_attr_changed,
1741 NULL, /* content_changed */
1742 NULL /* order_changed */
1743 };
1746 /**
1747 * \param selection Should not be NULL.
1748 */
1749 static void
1750 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1751 {
1752 int n_selected = 0;
1753 Inkscape::XML::Node *repr = NULL;
1755 purge_repr_listener( tbl, tbl );
1757 for (GSList const *items = selection->itemList();
1758 items != NULL;
1759 items = items->next)
1760 {
1761 if (SP_IS_STAR((SPItem *) items->data)) {
1762 n_selected++;
1763 repr = SP_OBJECT_REPR((SPItem *) items->data);
1764 }
1765 }
1767 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1769 if (n_selected == 0) {
1770 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1771 } else if (n_selected == 1) {
1772 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1774 if (repr) {
1775 g_object_set_data( tbl, "repr", repr );
1776 Inkscape::GC::anchor(repr);
1777 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1778 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1779 }
1780 } else {
1781 // FIXME: implement averaging of all parameters for multiple selected stars
1782 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1783 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1784 }
1785 }
1788 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
1789 {
1790 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1791 // callbacks to lump all the changes for all selected objects in one undo step
1793 GtkAdjustment *adj = 0;
1795 // fixme: make settable in prefs!
1796 gint mag = 5;
1797 gdouble prop = 0.5;
1798 gboolean flat = FALSE;
1799 gdouble randomized = 0;
1800 gdouble rounded = 0;
1802 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1803 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1805 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1806 gtk_action_set_sensitive( sb2, !flat );
1808 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1809 gtk_adjustment_set_value(adj, mag);
1810 gtk_adjustment_value_changed(adj);
1812 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1813 gtk_adjustment_set_value(adj, prop);
1814 gtk_adjustment_value_changed(adj);
1816 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1817 gtk_adjustment_set_value(adj, rounded);
1818 gtk_adjustment_value_changed(adj);
1820 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1821 gtk_adjustment_set_value(adj, randomized);
1822 gtk_adjustment_value_changed(adj);
1823 }
1826 void
1827 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1828 {
1829 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1830 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1831 GtkWidget *l = gtk_label_new(NULL);
1832 gtk_label_set_markup(GTK_LABEL(l), title);
1833 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1834 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1835 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1836 }
1839 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1840 {
1841 {
1842 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1843 ege_output_action_set_use_markup( act, TRUE );
1844 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1845 g_object_set_data( holder, "mode_action", act );
1846 }
1848 {
1849 //EgeAdjustmentAction* calligraphy_angle = 0;
1850 EgeAdjustmentAction* eact = 0;
1851 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1852 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1854 /* Flatsided checkbox */
1855 {
1856 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1858 GtkTreeIter iter;
1859 gtk_list_store_append( model, &iter );
1860 gtk_list_store_set( model, &iter,
1861 0, _("Polygon"),
1862 1, _("Regular polygon (with one handle) instead of a star"),
1863 2, "star_flat",
1864 -1 );
1866 gtk_list_store_append( model, &iter );
1867 gtk_list_store_set( model, &iter,
1868 0, _("Star"),
1869 1, _("Star instead of a regular polygon (with one handle)"),
1870 2, "star_angled",
1871 -1 );
1873 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
1874 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1875 g_object_set_data( holder, "flat_action", act );
1877 ege_select_one_action_set_appearance( act, "full" );
1878 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1879 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1880 ege_select_one_action_set_icon_column( act, 2 );
1881 ege_select_one_action_set_tooltip_column( act, 1 );
1883 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1884 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1885 }
1887 /* Magnitude */
1888 {
1889 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
1890 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
1891 eact = create_adjustment_action( "MagnitudeAction",
1892 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
1893 "tools.shapes.star", "magnitude", 3,
1894 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1895 3, 1024, 1, 5,
1896 labels, values, G_N_ELEMENTS(labels),
1897 sp_stb_magnitude_value_changed,
1898 1.0, 0 );
1899 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1900 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1901 }
1903 /* Spoke ratio */
1904 {
1905 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
1906 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
1907 eact = create_adjustment_action( "SpokeAction",
1908 _("Spoke ratio"), _("Spoke ratio:"),
1909 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1910 // Base radius is the same for the closest handle.
1911 _("Base radius to tip radius ratio"),
1912 "tools.shapes.star", "proportion", 0.5,
1913 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1914 0.01, 1.0, 0.01, 0.1,
1915 labels, values, G_N_ELEMENTS(labels),
1916 sp_stb_proportion_value_changed );
1917 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1918 g_object_set_data( holder, "prop_action", eact );
1919 }
1921 if ( !isFlatSided ) {
1922 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1923 } else {
1924 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1925 }
1927 /* Roundedness */
1928 {
1929 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
1930 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
1931 eact = create_adjustment_action( "RoundednessAction",
1932 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1933 "tools.shapes.star", "rounded", 0.0,
1934 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1935 -10.0, 10.0, 0.01, 0.1,
1936 labels, values, G_N_ELEMENTS(labels),
1937 sp_stb_rounded_value_changed );
1938 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1939 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1940 }
1942 /* Randomization */
1943 {
1944 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
1945 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
1946 eact = create_adjustment_action( "RandomizationAction",
1947 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
1948 "tools.shapes.star", "randomized", 0.0,
1949 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1950 -10.0, 10.0, 0.001, 0.01,
1951 labels, values, G_N_ELEMENTS(labels),
1952 sp_stb_randomized_value_changed, 0.1, 3 );
1953 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1954 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1955 }
1956 }
1958 {
1959 /* Reset */
1960 {
1961 GtkAction* act = gtk_action_new( "StarResetAction",
1962 _("Defaults"),
1963 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1964 GTK_STOCK_CLEAR );
1965 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1966 gtk_action_group_add_action( mainActions, act );
1967 gtk_action_set_sensitive( act, TRUE );
1968 }
1969 }
1971 sigc::connection *connection = new sigc::connection(
1972 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1973 );
1974 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1975 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1976 }
1979 //########################
1980 //## Rect ##
1981 //########################
1983 static void sp_rtb_sensitivize( GObject *tbl )
1984 {
1985 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
1986 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
1987 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
1989 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
1990 gtk_action_set_sensitive( not_rounded, FALSE );
1991 } else {
1992 gtk_action_set_sensitive( not_rounded, TRUE );
1993 }
1994 }
1997 static void
1998 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
1999 void (*setter)(SPRect *, gdouble))
2000 {
2001 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2003 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2004 SPUnit const *unit = tracker->getActiveUnit();
2006 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2007 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
2008 }
2010 // quit if run by the attr_changed listener
2011 if (g_object_get_data( tbl, "freeze" )) {
2012 return;
2013 }
2015 // in turn, prevent listener from responding
2016 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2018 bool modmade = false;
2019 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2020 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2021 if (SP_IS_RECT(items->data)) {
2022 if (adj->value != 0) {
2023 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2024 } else {
2025 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2026 }
2027 modmade = true;
2028 }
2029 }
2031 sp_rtb_sensitivize( tbl );
2033 if (modmade) {
2034 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2035 _("Change rectangle"));
2036 }
2038 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2039 }
2041 static void
2042 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2043 {
2044 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2045 }
2047 static void
2048 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2049 {
2050 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2051 }
2053 static void
2054 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2055 {
2056 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2057 }
2059 static void
2060 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2061 {
2062 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2063 }
2067 static void
2068 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2069 {
2070 GtkAdjustment *adj = 0;
2072 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2073 gtk_adjustment_set_value(adj, 0.0);
2074 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2075 gtk_adjustment_value_changed(adj);
2077 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2078 gtk_adjustment_set_value(adj, 0.0);
2079 gtk_adjustment_value_changed(adj);
2081 sp_rtb_sensitivize( obj );
2082 }
2084 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2085 gchar const */*old_value*/, gchar const */*new_value*/,
2086 bool /*is_interactive*/, gpointer data)
2087 {
2088 GObject *tbl = G_OBJECT(data);
2090 // quit if run by the _changed callbacks
2091 if (g_object_get_data( tbl, "freeze" )) {
2092 return;
2093 }
2095 // in turn, prevent callbacks from responding
2096 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2098 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2099 SPUnit const *unit = tracker->getActiveUnit();
2101 gpointer item = g_object_get_data( tbl, "item" );
2102 if (item && SP_IS_RECT(item)) {
2103 {
2104 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2105 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2106 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2107 }
2109 {
2110 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2111 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2112 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2113 }
2115 {
2116 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2117 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2118 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2119 }
2121 {
2122 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2123 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2124 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2125 }
2126 }
2128 sp_rtb_sensitivize( tbl );
2130 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2131 }
2134 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2135 NULL, /* child_added */
2136 NULL, /* child_removed */
2137 rect_tb_event_attr_changed,
2138 NULL, /* content_changed */
2139 NULL /* order_changed */
2140 };
2142 /**
2143 * \param selection should not be NULL.
2144 */
2145 static void
2146 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2147 {
2148 int n_selected = 0;
2149 Inkscape::XML::Node *repr = NULL;
2150 SPItem *item = NULL;
2152 if ( g_object_get_data( tbl, "repr" ) ) {
2153 g_object_set_data( tbl, "item", NULL );
2154 }
2155 purge_repr_listener( tbl, tbl );
2157 for (GSList const *items = selection->itemList();
2158 items != NULL;
2159 items = items->next) {
2160 if (SP_IS_RECT((SPItem *) items->data)) {
2161 n_selected++;
2162 item = (SPItem *) items->data;
2163 repr = SP_OBJECT_REPR(item);
2164 }
2165 }
2167 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2169 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2171 if (n_selected == 0) {
2172 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2174 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2175 gtk_action_set_sensitive(w, FALSE);
2176 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2177 gtk_action_set_sensitive(h, FALSE);
2179 } else if (n_selected == 1) {
2180 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2181 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2183 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2184 gtk_action_set_sensitive(w, TRUE);
2185 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2186 gtk_action_set_sensitive(h, TRUE);
2188 if (repr) {
2189 g_object_set_data( tbl, "repr", repr );
2190 g_object_set_data( tbl, "item", item );
2191 Inkscape::GC::anchor(repr);
2192 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2193 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2194 }
2195 } else {
2196 // FIXME: implement averaging of all parameters for multiple selected
2197 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2198 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2199 sp_rtb_sensitivize( tbl );
2200 }
2201 }
2204 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2205 {
2206 EgeAdjustmentAction* eact = 0;
2208 {
2209 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2210 ege_output_action_set_use_markup( act, TRUE );
2211 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2212 g_object_set_data( holder, "mode_action", act );
2213 }
2215 // rx/ry units menu: create
2216 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2217 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2218 // fixme: add % meaning per cent of the width/height
2219 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2220 g_object_set_data( holder, "tracker", tracker );
2222 /* W */
2223 {
2224 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2225 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2226 eact = create_adjustment_action( "RectWidthAction",
2227 _("Width"), _("W:"), _("Width of rectangle"),
2228 "tools.shapes.rect", "width", 0,
2229 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2230 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2231 labels, values, G_N_ELEMENTS(labels),
2232 sp_rtb_width_value_changed );
2233 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2234 g_object_set_data( holder, "width_action", eact );
2235 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2236 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2237 }
2239 /* H */
2240 {
2241 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2242 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2243 eact = create_adjustment_action( "RectHeightAction",
2244 _("Height"), _("H:"), _("Height of rectangle"),
2245 "tools.shapes.rect", "height", 0,
2246 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2247 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2248 labels, values, G_N_ELEMENTS(labels),
2249 sp_rtb_height_value_changed );
2250 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2251 g_object_set_data( holder, "height_action", eact );
2252 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2253 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2254 }
2256 /* rx */
2257 {
2258 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2259 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2260 eact = create_adjustment_action( "RadiusXAction",
2261 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2262 "tools.shapes.rect", "rx", 0,
2263 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2264 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2265 labels, values, G_N_ELEMENTS(labels),
2266 sp_rtb_rx_value_changed);
2267 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2268 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2269 }
2271 /* ry */
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( "RadiusYAction",
2276 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2277 "tools.shapes.rect", "ry", 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_ry_value_changed);
2282 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2283 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2284 }
2286 // add the units menu
2287 {
2288 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2289 gtk_action_group_add_action( mainActions, act );
2290 }
2292 /* Reset */
2293 {
2294 InkAction* inky = ink_action_new( "RectResetAction",
2295 _("Not rounded"),
2296 _("Make corners sharp"),
2297 "squared_corner",
2298 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2299 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2300 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2301 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2302 g_object_set_data( holder, "not_rounded", inky );
2303 }
2305 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2306 sp_rtb_sensitivize( holder );
2308 sigc::connection *connection = new sigc::connection(
2309 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2310 );
2311 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2312 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2313 }
2315 //########################
2316 //## 3D Box ##
2317 //########################
2319 static void sp_3dbox_toggle_vp_changed (GtkToggleAction */*act*/, GObject *dataKludge, Box3D::Axis axis)
2320 {
2321 SPDesktop *desktop = (SPDesktop *) g_object_get_data (dataKludge, "desktop");
2322 SPDocument *document = sp_desktop_document (desktop);
2323 Box3D::Perspective3D *persp = document->current_perspective;
2325 g_return_if_fail (is_single_axis_direction (axis));
2326 g_return_if_fail (persp);
2328 persp->toggle_boxes (axis);
2330 gchar *str;
2331 switch (axis) {
2332 case Box3D::X:
2333 str = g_strdup ("box3d_angle_x_action");
2334 break;
2335 case Box3D::Y:
2336 str = g_strdup ("box3d_angle_y_action");
2337 break;
2338 case Box3D::Z:
2339 str = g_strdup ("box3d_angle_z_action");
2340 break;
2341 default:
2342 return;
2343 }
2344 GtkAction* angle_action = GTK_ACTION (g_object_get_data (dataKludge, str));
2345 if (angle_action) {
2346 gtk_action_set_sensitive (angle_action, !persp->get_vanishing_point (axis)->is_finite() );
2347 }
2349 // FIXME: Given how it is realized in the other tools, this is probably not the right way to do it,
2350 // but without the if construct, we get continuous segfaults. Needs further investigation.
2351 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2352 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
2353 _("3D Box: Change perspective"));
2354 }
2355 }
2357 static void sp_3dbox_toggle_vp_x_changed(GtkToggleAction *act, GObject *dataKludge)
2358 {
2359 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::X);
2360 }
2362 static void sp_3dbox_toggle_vp_y_changed(GtkToggleAction *act, GObject *dataKludge)
2363 {
2364 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Y);
2365 }
2367 static void sp_3dbox_toggle_vp_z_changed(GtkToggleAction *act, GObject *dataKludge)
2368 {
2369 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Z);
2370 }
2372 static void sp_3dbox_vp_angle_changed(GtkAdjustment *adj, GObject *dataKludge, Box3D::Axis axis )
2373 {
2374 SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
2375 Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
2377 if (persp) {
2378 double angle = adj->value * M_PI/180;
2379 persp->set_infinite_direction (axis, NR::Point (cos (angle), sin (angle)));
2381 // FIXME: See comment above; without the if construct we get segfaults during undo.
2382 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2383 sp_document_maybe_done(sp_desktop_document(desktop), "perspectiveangle", SP_VERB_CONTEXT_3DBOX,
2384 _("3D Box: Change perspective"));
2385 }
2386 }
2387 //g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
2388 }
2390 static void sp_3dbox_vpx_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2391 {
2392 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::X);
2393 }
2395 static void sp_3dbox_vpy_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2396 {
2397 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Y);
2398 }
2400 static void sp_3dbox_vpz_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2401 {
2402 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Z);
2403 }
2405 // normalize angle so that it lies in the interval [0,360]
2406 static double sp_3dbox_normalize_angle (double a) {
2407 double angle = a + ((int) (a/360.0))*360;
2408 if (angle < 0) {
2409 angle += 360.0;
2410 }
2411 return angle;
2412 }
2414 static void sp_3dbox_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const *name,
2415 gchar const */*old_value*/, gchar const */*new_value*/,
2416 bool /*is_interactive*/, gpointer data)
2417 {
2418 GtkWidget *tbl = GTK_WIDGET(data);
2420 // FIXME: if we check for "freeze" as in other tools, no action is performed at all ...
2421 /***
2422 // quit if run by the _changed callbacks
2423 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2424 return;
2425 }
2427 // in turn, prevent callbacks from responding
2428 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2429 ***/
2431 if (!strcmp(name, "inkscape:perspective")) {
2432 GtkAdjustment *adj = 0;
2433 double angle;
2434 SPDesktop *desktop = (SPDesktop *) g_object_get_data(G_OBJECT(tbl), "desktop");
2435 Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
2437 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_x"));
2438 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::X)->get_angle());
2439 gtk_adjustment_set_value(adj, angle);
2441 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_y"));
2442 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Y)->get_angle());
2443 gtk_adjustment_set_value(adj, angle);
2445 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_z"));
2446 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Z)->get_angle());
2447 gtk_adjustment_set_value(adj, angle);
2448 }
2449 }
2451 static Inkscape::XML::NodeEventVector sp_3dbox_tb_repr_events =
2452 {
2453 NULL, /* child_added */
2454 NULL, /* child_removed */
2455 sp_3dbox_tb_event_attr_changed,
2456 NULL, /* content_changed */
2457 NULL /* order_changed */
2458 };
2460 /**
2461 * \param selection Should not be NULL.
2462 */
2463 static void
2464 sp_3dbox_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2465 {
2466 Inkscape::XML::Node *repr = NULL;
2467 purge_repr_listener(tbl, tbl);
2469 SPItem *item = selection->singleItem();
2470 if (item) {
2471 repr = SP_OBJECT_REPR(item);
2472 if (repr) {
2473 g_object_set_data(tbl, "repr", repr);
2474 Inkscape::GC::anchor(repr);
2475 sp_repr_add_listener(repr, &sp_3dbox_tb_repr_events, tbl);
2476 sp_repr_synthesize_events(repr, &sp_3dbox_tb_repr_events, tbl);
2477 }
2478 }
2479 }
2481 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2482 {
2483 EgeAdjustmentAction* eact = 0;
2484 SPDocument *document = sp_desktop_document (desktop);
2485 Box3D::Perspective3D *persp = document->current_perspective;
2486 bool toggled = false;
2488 /* angle of VP in X direction */
2489 eact = create_adjustment_action("3DBoxPosAngleXAction",
2490 _("Angle X"), _("Angle X:"), _("Angle of infinite vanishing point in X direction"),
2491 "tools.shapes.3dbox", "dir_vp_x", persp->get_vanishing_point (Box3D::X)->get_angle(),
2492 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2493 0.0, 360.0, 1.0, 10.0,
2494 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2495 sp_3dbox_vpx_angle_changed,
2496 0.1, 1);
2497 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2498 g_object_set_data(holder, "box3d_angle_x_action", eact);
2499 if (!persp->get_vanishing_point (Box3D::X)->is_finite()) {
2500 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2501 } else {
2502 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2503 }
2505 /* toggle VP in X direction */
2506 {
2507 InkToggleAction* act = ink_toggle_action_new("3DBoxVPXAction",
2508 _("Toggle VP in X direction"),
2509 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2510 "toggle_vp_x",
2511 Inkscape::ICON_SIZE_DECORATION);
2512 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2513 if (persp) {
2514 toggled = !persp->get_vanishing_point(Box3D::X)->is_finite();
2515 }
2516 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2517 /* we connect the signal after setting the state to avoid switching the state again */
2518 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_x_changed), holder);
2519 }
2521 /* angle of VP in Y direction */
2522 eact = create_adjustment_action("3DBoxPosAngleYAction",
2523 _("Angle Y"), _("Angle Y:"), _("Angle of infinite vanishing point in Y direction"),
2524 "tools.shapes.3dbox", "dir_vp_y", persp->get_vanishing_point (Box3D::Y)->get_angle(),
2525 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2526 0.0, 360.0, 1.0, 10.0,
2527 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2528 sp_3dbox_vpy_angle_changed,
2529 0.1, 1);
2530 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2531 g_object_set_data(holder, "box3d_angle_y_action", eact);
2532 if (!persp->get_vanishing_point (Box3D::Y)->is_finite()) {
2533 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2534 } else {
2535 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2536 }
2538 /* toggle VP in Y direction */
2539 {
2540 InkToggleAction* act = ink_toggle_action_new("3DBoxVPYAction",
2541 _("Toggle VP in Y direction"),
2542 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2543 "toggle_vp_y",
2544 Inkscape::ICON_SIZE_DECORATION);
2545 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2546 if (persp) {
2547 toggled = !persp->get_vanishing_point(Box3D::Y)->is_finite();
2548 }
2549 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2550 /* we connect the signal after setting the state to avoid switching the state again */
2551 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_y_changed), holder);
2552 }
2554 /* angle of VP in Z direction */
2555 eact = create_adjustment_action("3DBoxPosAngleZAction",
2556 _("Angle Z"), _("Angle Z:"), _("Angle of infinite vanishing point in Z direction"),
2557 "tools.shapes.3dbox", "dir_vp_z", persp->get_vanishing_point (Box3D::Z)->get_angle(),
2558 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2559 0.0, 360.0, 1.0, 10.0,
2560 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2561 sp_3dbox_vpz_angle_changed,
2562 0.1, 1);
2564 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2565 g_object_set_data(holder, "box3d_angle_z_action", eact);
2566 if (!persp->get_vanishing_point (Box3D::Z)->is_finite()) {
2567 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2568 } else {
2569 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2570 }
2572 /* toggle VP in Z direction */
2573 {
2574 InkToggleAction* act = ink_toggle_action_new("3DBoxVPZAction",
2575 _("Toggle VP in Z direction"),
2576 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
2577 "toggle_vp_z",
2578 Inkscape::ICON_SIZE_DECORATION);
2579 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2580 if (persp) {
2581 toggled = !persp->get_vanishing_point(Box3D::Z)->is_finite();
2582 }
2583 /* we connect the signal after setting the state to avoid switching the state again */
2584 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2585 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_z_changed), holder);
2586 }
2588 sigc::connection *connection = new sigc::connection(
2589 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_3dbox_toolbox_selection_changed), (GObject *)holder))
2590 );
2591 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
2592 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
2593 }
2595 //########################
2596 //## Spiral ##
2597 //########################
2599 static void
2600 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2601 {
2602 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2604 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2605 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2606 }
2608 // quit if run by the attr_changed listener
2609 if (g_object_get_data( tbl, "freeze" )) {
2610 return;
2611 }
2613 // in turn, prevent listener from responding
2614 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2616 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2618 bool modmade = false;
2619 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2620 items != NULL;
2621 items = items->next)
2622 {
2623 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2624 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2625 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2626 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2627 modmade = true;
2628 }
2629 }
2631 g_free(namespaced_name);
2633 if (modmade) {
2634 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2635 _("Change spiral"));
2636 }
2638 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2639 }
2641 static void
2642 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2643 {
2644 sp_spl_tb_value_changed(adj, tbl, "revolution");
2645 }
2647 static void
2648 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2649 {
2650 sp_spl_tb_value_changed(adj, tbl, "expansion");
2651 }
2653 static void
2654 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2655 {
2656 sp_spl_tb_value_changed(adj, tbl, "t0");
2657 }
2659 static void
2660 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
2661 {
2662 GtkWidget *tbl = GTK_WIDGET(obj);
2664 GtkAdjustment *adj;
2666 // fixme: make settable
2667 gdouble rev = 5;
2668 gdouble exp = 1.0;
2669 gdouble t0 = 0.0;
2671 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2672 gtk_adjustment_set_value(adj, rev);
2673 gtk_adjustment_value_changed(adj);
2675 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2676 gtk_adjustment_set_value(adj, exp);
2677 gtk_adjustment_value_changed(adj);
2679 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2680 gtk_adjustment_set_value(adj, t0);
2681 gtk_adjustment_value_changed(adj);
2683 spinbutton_defocus(GTK_OBJECT(tbl));
2684 }
2687 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2688 gchar const */*old_value*/, gchar const */*new_value*/,
2689 bool /*is_interactive*/, gpointer data)
2690 {
2691 GtkWidget *tbl = GTK_WIDGET(data);
2693 // quit if run by the _changed callbacks
2694 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2695 return;
2696 }
2698 // in turn, prevent callbacks from responding
2699 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2701 GtkAdjustment *adj;
2702 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2703 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2705 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2706 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2708 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2709 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2711 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2712 }
2715 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2716 NULL, /* child_added */
2717 NULL, /* child_removed */
2718 spiral_tb_event_attr_changed,
2719 NULL, /* content_changed */
2720 NULL /* order_changed */
2721 };
2723 static void
2724 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2725 {
2726 int n_selected = 0;
2727 Inkscape::XML::Node *repr = NULL;
2729 purge_repr_listener( tbl, tbl );
2731 for (GSList const *items = selection->itemList();
2732 items != NULL;
2733 items = items->next)
2734 {
2735 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2736 n_selected++;
2737 repr = SP_OBJECT_REPR((SPItem *) items->data);
2738 }
2739 }
2741 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2743 if (n_selected == 0) {
2744 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2745 } else if (n_selected == 1) {
2746 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2748 if (repr) {
2749 g_object_set_data( tbl, "repr", repr );
2750 Inkscape::GC::anchor(repr);
2751 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2752 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2753 }
2754 } else {
2755 // FIXME: implement averaging of all parameters for multiple selected
2756 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2757 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2758 }
2759 }
2762 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2763 {
2764 EgeAdjustmentAction* eact = 0;
2766 {
2767 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2768 ege_output_action_set_use_markup( act, TRUE );
2769 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2770 g_object_set_data( holder, "mode_action", act );
2771 }
2773 /* Revolution */
2774 {
2775 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
2776 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2777 eact = create_adjustment_action( "SpiralRevolutionAction",
2778 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
2779 "tools.shapes.spiral", "revolution", 3.0,
2780 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2781 0.01, 1024.0, 0.1, 1.0,
2782 labels, values, G_N_ELEMENTS(labels),
2783 sp_spl_tb_revolution_value_changed, 1, 2);
2784 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2785 }
2787 /* Expansion */
2788 {
2789 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
2790 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
2791 eact = create_adjustment_action( "SpiralExpansionAction",
2792 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2793 "tools.shapes.spiral", "expansion", 1.0,
2794 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2795 0.0, 1000.0, 0.01, 1.0,
2796 labels, values, G_N_ELEMENTS(labels),
2797 sp_spl_tb_expansion_value_changed);
2798 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2799 }
2801 /* T0 */
2802 {
2803 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
2804 gdouble values[] = {0, 0.5, 0.9};
2805 eact = create_adjustment_action( "SpiralT0Action",
2806 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2807 "tools.shapes.spiral", "t0", 0.0,
2808 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2809 0.0, 0.999, 0.01, 1.0,
2810 labels, values, G_N_ELEMENTS(labels),
2811 sp_spl_tb_t0_value_changed);
2812 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2813 }
2815 /* Reset */
2816 {
2817 InkAction* inky = ink_action_new( "SpiralResetAction",
2818 _("Defaults"),
2819 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2820 GTK_STOCK_CLEAR,
2821 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2822 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2823 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2824 }
2827 sigc::connection *connection = new sigc::connection(
2828 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2829 );
2830 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2831 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2832 }
2834 //########################
2835 //## Pen/Pencil ##
2836 //########################
2839 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2840 {
2841 // Put stuff here
2842 }
2844 static void sp_pencil_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2845 {
2846 // Put stuff here
2847 }
2849 //########################
2850 //## Tweak ##
2851 //########################
2853 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2854 {
2855 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
2856 }
2858 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2859 {
2860 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
2861 }
2863 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
2864 {
2865 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2866 }
2868 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
2869 {
2870 int mode = ege_select_one_action_get_active( act );
2871 prefs_set_int_attribute("tools.tweak", "mode", mode);
2873 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
2874 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
2875 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
2876 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
2877 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
2878 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
2879 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
2880 if (doh) gtk_action_set_sensitive (doh, TRUE);
2881 if (dos) gtk_action_set_sensitive (dos, TRUE);
2882 if (dol) gtk_action_set_sensitive (dol, TRUE);
2883 if (doo) gtk_action_set_sensitive (doo, TRUE);
2884 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
2885 if (fid) gtk_action_set_sensitive (fid, FALSE);
2886 } else {
2887 if (doh) gtk_action_set_sensitive (doh, FALSE);
2888 if (dos) gtk_action_set_sensitive (dos, FALSE);
2889 if (dol) gtk_action_set_sensitive (dol, FALSE);
2890 if (doo) gtk_action_set_sensitive (doo, FALSE);
2891 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
2892 if (fid) gtk_action_set_sensitive (fid, TRUE);
2893 }
2894 }
2896 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2897 {
2898 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
2899 }
2901 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
2902 bool show = gtk_toggle_action_get_active( act );
2903 prefs_set_int_attribute ("tools.tweak", "doh", show ? 1 : 0);
2904 }
2905 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
2906 bool show = gtk_toggle_action_get_active( act );
2907 prefs_set_int_attribute ("tools.tweak", "dos", show ? 1 : 0);
2908 }
2909 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
2910 bool show = gtk_toggle_action_get_active( act );
2911 prefs_set_int_attribute ("tools.tweak", "dol", show ? 1 : 0);
2912 }
2913 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
2914 bool show = gtk_toggle_action_get_active( act );
2915 prefs_set_int_attribute ("tools.tweak", "doo", show ? 1 : 0);
2916 }
2918 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2919 {
2920 {
2921 /* Width */
2922 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
2923 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2924 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
2925 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
2926 "tools.tweak", "width", 15,
2927 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
2928 1, 100, 1.0, 10.0,
2929 labels, values, G_N_ELEMENTS(labels),
2930 sp_tweak_width_value_changed, 0.01, 0, 100 );
2931 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2932 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2933 }
2936 {
2937 /* Force */
2938 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
2939 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
2940 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
2941 _("Force"), _("Force:"), _("The force of the tweak action"),
2942 "tools.tweak", "force", 20,
2943 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
2944 1, 100, 1.0, 10.0,
2945 labels, values, G_N_ELEMENTS(labels),
2946 sp_tweak_force_value_changed, 0.01, 0, 100 );
2947 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2948 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2949 }
2951 /* Mode */
2952 {
2953 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2955 GtkTreeIter iter;
2956 gtk_list_store_append( model, &iter );
2957 gtk_list_store_set( model, &iter,
2958 0, _("Push mode"),
2959 1, _("Push parts of paths in any direction"),
2960 2, "tweak_push_mode",
2961 -1 );
2963 gtk_list_store_append( model, &iter );
2964 gtk_list_store_set( model, &iter,
2965 0, _("Shrink mode"),
2966 1, _("Shrink (inset) parts of paths"),
2967 2, "tweak_shrink_mode",
2968 -1 );
2970 gtk_list_store_append( model, &iter );
2971 gtk_list_store_set( model, &iter,
2972 0, _("Grow mode"),
2973 1, _("Grow (outset) parts of paths"),
2974 2, "tweak_grow_mode",
2975 -1 );
2977 gtk_list_store_append( model, &iter );
2978 gtk_list_store_set( model, &iter,
2979 0, _("Attract mode"),
2980 1, _("Attract parts of paths towards cursor"),
2981 2, "tweak_attract_mode",
2982 -1 );
2984 gtk_list_store_append( model, &iter );
2985 gtk_list_store_set( model, &iter,
2986 0, _("Repel mode"),
2987 1, _("Repel parts of paths from cursor"),
2988 2, "tweak_repel_mode",
2989 -1 );
2991 gtk_list_store_append( model, &iter );
2992 gtk_list_store_set( model, &iter,
2993 0, _("Roughen mode"),
2994 1, _("Roughen parts of paths"),
2995 2, "tweak_roughen_mode",
2996 -1 );
2998 gtk_list_store_append( model, &iter );
2999 gtk_list_store_set( model, &iter,
3000 0, _("Color paint mode"),
3001 1, _("Paint the tool's color upon selected objects"),
3002 2, "tweak_colorpaint_mode",
3003 -1 );
3005 gtk_list_store_append( model, &iter );
3006 gtk_list_store_set( model, &iter,
3007 0, _("Color jitter mode"),
3008 1, _("Jitter the colors of selected objects"),
3009 2, "tweak_colorjitter_mode",
3010 -1 );
3012 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
3013 g_object_set( act, "short_label", _("Mode:"), NULL );
3014 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3015 g_object_set_data( holder, "mode_action", act );
3017 ege_select_one_action_set_appearance( act, "full" );
3018 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3019 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3020 ege_select_one_action_set_icon_column( act, 2 );
3021 ege_select_one_action_set_tooltip_column( act, 1 );
3023 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3024 ege_select_one_action_set_active( act, mode );
3025 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3027 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3028 }
3030 guint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3032 {
3033 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3034 ege_output_action_set_use_markup( act, TRUE );
3035 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3036 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3037 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3038 g_object_set_data( holder, "tweak_channels_label", act);
3039 }
3041 {
3042 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3043 _("Hue"),
3044 _("In color mode, act on objects' hue"),
3045 NULL,
3046 Inkscape::ICON_SIZE_DECORATION );
3047 g_object_set( act, "short_label", _("H"), NULL );
3048 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3049 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3050 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doh", 1 ) );
3051 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3052 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3053 g_object_set_data( holder, "tweak_doh", act);
3054 }
3055 {
3056 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3057 _("Saturation"),
3058 _("In color mode, act on objects' saturation"),
3059 NULL,
3060 Inkscape::ICON_SIZE_DECORATION );
3061 g_object_set( act, "short_label", _("S"), NULL );
3062 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3063 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3064 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dos", 1 ) );
3065 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3066 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3067 g_object_set_data( holder, "tweak_dos", act );
3068 }
3069 {
3070 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3071 _("Lightness"),
3072 _("In color mode, act on objects' lightness"),
3073 NULL,
3074 Inkscape::ICON_SIZE_DECORATION );
3075 g_object_set( act, "short_label", _("L"), NULL );
3076 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3077 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3078 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dol", 1 ) );
3079 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3080 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3081 g_object_set_data( holder, "tweak_dol", act );
3082 }
3083 {
3084 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3085 _("Opacity"),
3086 _("In color mode, act on objects' opacity"),
3087 NULL,
3088 Inkscape::ICON_SIZE_DECORATION );
3089 g_object_set( act, "short_label", _("O"), NULL );
3090 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3091 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3092 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doo", 1 ) );
3093 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3094 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3095 g_object_set_data( holder, "tweak_doo", act );
3096 }
3098 { /* Fidelity */
3099 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3100 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3101 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3102 _("Fidelity"), _("Fidelity:"),
3103 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3104 "tools.tweak", "fidelity", 50,
3105 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3106 1, 100, 1.0, 10.0,
3107 labels, values, G_N_ELEMENTS(labels),
3108 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3109 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3110 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3111 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3112 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3113 g_object_set_data( holder, "tweak_fidelity", eact );
3114 }
3117 /* Use Pressure button */
3118 {
3119 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3120 _("Pressure"),
3121 _("Use the pressure of the input device to alter the force of tweak action"),
3122 "use_pressure",
3123 Inkscape::ICON_SIZE_DECORATION );
3124 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3125 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3126 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
3127 }
3129 }
3132 //########################
3133 //## Calligraphy ##
3134 //########################
3136 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3137 {
3138 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
3139 }
3141 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3142 {
3143 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
3144 }
3146 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3147 {
3148 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
3149 }
3151 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3152 {
3153 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
3154 }
3156 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3157 {
3158 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
3159 }
3161 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3162 {
3163 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
3164 }
3166 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3167 {
3168 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
3169 }
3171 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3172 {
3173 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
3174 }
3176 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3177 {
3178 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3179 }
3181 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer /*data*/ )
3182 {
3183 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
3184 }
3186 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
3187 {
3188 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3190 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
3191 }
3193 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
3194 {
3195 // FIXME: make defaults settable via Inkscape Options
3196 struct KeyValue {
3197 char const *key;
3198 double value;
3199 } const key_values[] = {
3200 {"mass", 0.02},
3201 {"wiggle", 0.0},
3202 {"angle", 30.0},
3203 {"width", 15},
3204 {"thinning", 0.1},
3205 {"tremor", 0.0},
3206 {"flatness", 0.9},
3207 {"cap_rounding", 0.0}
3208 };
3210 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
3211 KeyValue const &kv = key_values[i];
3212 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
3213 if ( adj ) {
3214 gtk_adjustment_set_value(adj, kv.value);
3215 }
3216 }
3217 }
3220 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3221 {
3222 {
3223 EgeAdjustmentAction* calligraphy_angle = 0;
3225 {
3226 /* Width */
3227 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
3228 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3229 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
3230 _("Pen Width"), _("Width:"),
3231 _("The width of the calligraphic pen (relative to the visible canvas area)"),
3232 "tools.calligraphic", "width", 15,
3233 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
3234 1, 100, 1.0, 10.0,
3235 labels, values, G_N_ELEMENTS(labels),
3236 sp_ddc_width_value_changed, 0.01, 0, 100 );
3237 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3238 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3239 }
3241 {
3242 /* Thinning */
3243 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
3244 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
3245 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
3246 _("Stroke Thinning"), _("Thinning:"),
3247 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
3248 "tools.calligraphic", "thinning", 0.1,
3249 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3250 -1.0, 1.0, 0.01, 0.1,
3251 labels, values, G_N_ELEMENTS(labels),
3252 sp_ddc_velthin_value_changed, 0.01, 2);
3253 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3254 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3255 }
3257 {
3258 /* Angle */
3259 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
3260 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3261 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
3262 _("Pen Angle"), _("Angle:"),
3263 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
3264 "tools.calligraphic", "angle", 30,
3265 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
3266 -90.0, 90.0, 1.0, 10.0,
3267 labels, values, G_N_ELEMENTS(labels),
3268 sp_ddc_angle_value_changed, 1, 0 );
3269 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3270 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3271 calligraphy_angle = eact;
3272 }
3274 {
3275 /* Fixation */
3276 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
3277 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
3278 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
3279 _("Fixation"), _("Fixation:"),
3280 _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
3281 "tools.calligraphic", "flatness", 0.9,
3282 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3283 0.0, 1.0, 0.01, 0.1,
3284 labels, values, G_N_ELEMENTS(labels),
3285 sp_ddc_flatness_value_changed, 0.01, 2 );
3286 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3287 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3288 }
3290 {
3291 /* Cap Rounding */
3292 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
3293 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
3294 // TRANSLATORS: "cap" means "end" (both start and finish) here
3295 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
3296 _("Cap rounding"), _("Caps:"),
3297 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
3298 "tools.calligraphic", "cap_rounding", 0.0,
3299 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3300 0.0, 5.0, 0.01, 0.1,
3301 labels, values, G_N_ELEMENTS(labels),
3302 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
3303 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3304 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3305 }
3307 {
3308 /* Tremor */
3309 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
3310 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
3311 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
3312 _("Stroke Tremor"), _("Tremor:"),
3313 _("Increase to make strokes rugged and trembling"),
3314 "tools.calligraphic", "tremor", 0.0,
3315 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3316 0.0, 1.0, 0.01, 0.1,
3317 labels, values, G_N_ELEMENTS(labels),
3318 sp_ddc_tremor_value_changed, 0.01, 2 );
3320 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3321 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3322 }
3324 {
3325 /* Wiggle */
3326 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
3327 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
3328 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
3329 _("Pen Wiggle"), _("Wiggle:"),
3330 _("Increase to make the pen waver and wiggle"),
3331 "tools.calligraphic", "wiggle", 0.0,
3332 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3333 0.0, 1.0, 0.01, 0.1,
3334 labels, values, G_N_ELEMENTS(labels),
3335 sp_ddc_wiggle_value_changed, 0.01, 2 );
3336 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3337 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3338 }
3340 {
3341 /* Mass */
3342 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
3343 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
3344 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
3345 _("Pen Mass"), _("Mass:"),
3346 _("Increase to make the pen drag behind, as if slowed by inertia"),
3347 "tools.calligraphic", "mass", 0.02,
3348 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3349 0.0, 1.0, 0.01, 0.1,
3350 labels, values, G_N_ELEMENTS(labels),
3351 sp_ddc_mass_value_changed, 0.01, 2 );
3352 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3353 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3354 }
3357 /* Trace Background button */
3358 {
3359 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
3360 _("Trace Background"),
3361 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
3362 "trace_background",
3363 Inkscape::ICON_SIZE_DECORATION );
3364 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3365 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
3366 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
3367 }
3369 /* Use Pressure button */
3370 {
3371 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
3372 _("Pressure"),
3373 _("Use the pressure of the input device to alter the width of the pen"),
3374 "use_pressure",
3375 Inkscape::ICON_SIZE_DECORATION );
3376 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3377 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
3378 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
3379 }
3381 /* Use Tilt button */
3382 {
3383 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
3384 _("Tilt"),
3385 _("Use the tilt of the input device to alter the angle of the pen's nib"),
3386 "use_tilt",
3387 Inkscape::ICON_SIZE_DECORATION );
3388 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3389 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
3390 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3391 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3392 }
3394 /* Reset */
3395 {
3396 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
3397 _("Defaults"),
3398 _("Reset all parameters to defaults"),
3399 GTK_STOCK_CLEAR );
3400 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
3401 gtk_action_group_add_action( mainActions, act );
3402 gtk_action_set_sensitive( act, TRUE );
3403 }
3404 }
3405 }
3408 //########################
3409 //## Circle / Arc ##
3410 //########################
3412 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
3413 {
3414 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
3415 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
3417 if (v1 == 0 && v2 == 0) {
3418 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
3419 gtk_action_set_sensitive( ocb, FALSE );
3420 gtk_action_set_sensitive( make_whole, FALSE );
3421 }
3422 } else {
3423 gtk_action_set_sensitive( ocb, TRUE );
3424 gtk_action_set_sensitive( make_whole, TRUE );
3425 }
3426 }
3428 static void
3429 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
3430 {
3431 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3433 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3434 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
3435 }
3437 // quit if run by the attr_changed listener
3438 if (g_object_get_data( tbl, "freeze" )) {
3439 return;
3440 }
3442 // in turn, prevent listener from responding
3443 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3445 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
3447 bool modmade = false;
3448 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3449 items != NULL;
3450 items = items->next)
3451 {
3452 SPItem *item = SP_ITEM(items->data);
3454 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
3456 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
3457 SPArc *arc = SP_ARC(item);
3459 if (!strcmp(value_name, "start"))
3460 ge->start = (adj->value * M_PI)/ 180;
3461 else
3462 ge->end = (adj->value * M_PI)/ 180;
3464 sp_genericellipse_normalize(ge);
3465 ((SPObject *)arc)->updateRepr();
3466 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
3468 modmade = true;
3469 }
3470 }
3472 g_free(namespaced_name);
3474 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
3476 sp_arctb_sensitivize( tbl, adj->value, other->value );
3478 if (modmade) {
3479 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
3480 _("Arc: Change start/end"));
3481 }
3483 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3484 }
3487 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
3488 {
3489 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
3490 }
3492 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
3493 {
3494 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
3495 }
3497 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
3498 {
3499 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3500 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3501 if ( ege_select_one_action_get_active( act ) != 0 ) {
3502 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
3503 } else {
3504 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
3505 }
3506 }
3508 // quit if run by the attr_changed listener
3509 if (g_object_get_data( tbl, "freeze" )) {
3510 return;
3511 }
3513 // in turn, prevent listener from responding
3514 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3516 bool modmade = false;
3518 if ( ege_select_one_action_get_active(act) != 0 ) {
3519 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3520 items != NULL;
3521 items = items->next)
3522 {
3523 if (SP_IS_ARC((SPItem *) items->data)) {
3524 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3525 repr->setAttribute("sodipodi:open", "true");
3526 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3527 modmade = true;
3528 }
3529 }
3530 } else {
3531 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3532 items != NULL;
3533 items = items->next)
3534 {
3535 if (SP_IS_ARC((SPItem *) items->data)) {
3536 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3537 repr->setAttribute("sodipodi:open", NULL);
3538 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3539 modmade = true;
3540 }
3541 }
3542 }
3544 if (modmade) {
3545 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
3546 _("Arc: Change open/closed"));
3547 }
3549 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3550 }
3552 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
3553 {
3554 GtkAdjustment *adj;
3555 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
3556 gtk_adjustment_set_value(adj, 0.0);
3557 gtk_adjustment_value_changed(adj);
3559 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
3560 gtk_adjustment_set_value(adj, 0.0);
3561 gtk_adjustment_value_changed(adj);
3563 spinbutton_defocus( GTK_OBJECT(obj) );
3564 }
3566 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3567 gchar const */*old_value*/, gchar const */*new_value*/,
3568 bool /*is_interactive*/, gpointer data)
3569 {
3570 GObject *tbl = G_OBJECT(data);
3572 // quit if run by the _changed callbacks
3573 if (g_object_get_data( tbl, "freeze" )) {
3574 return;
3575 }
3577 // in turn, prevent callbacks from responding
3578 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3580 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
3581 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
3583 GtkAdjustment *adj1,*adj2;
3584 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
3585 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
3586 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
3587 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
3589 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
3591 char const *openstr = NULL;
3592 openstr = repr->attribute("sodipodi:open");
3593 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
3595 if (openstr) {
3596 ege_select_one_action_set_active( ocb, 1 );
3597 } else {
3598 ege_select_one_action_set_active( ocb, 0 );
3599 }
3601 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3602 }
3604 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
3605 NULL, /* child_added */
3606 NULL, /* child_removed */
3607 arc_tb_event_attr_changed,
3608 NULL, /* content_changed */
3609 NULL /* order_changed */
3610 };
3613 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3614 {
3615 int n_selected = 0;
3616 Inkscape::XML::Node *repr = NULL;
3618 purge_repr_listener( tbl, tbl );
3620 for (GSList const *items = selection->itemList();
3621 items != NULL;
3622 items = items->next)
3623 {
3624 if (SP_IS_ARC((SPItem *) items->data)) {
3625 n_selected++;
3626 repr = SP_OBJECT_REPR((SPItem *) items->data);
3627 }
3628 }
3630 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3632 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3633 if (n_selected == 0) {
3634 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3635 } else if (n_selected == 1) {
3636 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3637 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3639 if (repr) {
3640 g_object_set_data( tbl, "repr", repr );
3641 Inkscape::GC::anchor(repr);
3642 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
3643 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
3644 }
3645 } else {
3646 // FIXME: implement averaging of all parameters for multiple selected
3647 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3648 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3649 sp_arctb_sensitivize( tbl, 1, 0 );
3650 }
3651 }
3654 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3655 {
3656 EgeAdjustmentAction* eact = 0;
3659 {
3660 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
3661 ege_output_action_set_use_markup( act, TRUE );
3662 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3663 g_object_set_data( holder, "mode_action", act );
3664 }
3666 /* Start */
3667 {
3668 eact = create_adjustment_action( "ArcStartAction",
3669 _("Start"), _("Start:"),
3670 _("The angle (in degrees) from the horizontal to the arc's start point"),
3671 "tools.shapes.arc", "start", 0.0,
3672 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
3673 -360.0, 360.0, 1.0, 10.0,
3674 0, 0, 0,
3675 sp_arctb_start_value_changed);
3676 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3677 }
3679 /* End */
3680 {
3681 eact = create_adjustment_action( "ArcEndAction",
3682 _("End"), _("End:"),
3683 _("The angle (in degrees) from the horizontal to the arc's end point"),
3684 "tools.shapes.arc", "end", 0.0,
3685 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3686 -360.0, 360.0, 1.0, 10.0,
3687 0, 0, 0,
3688 sp_arctb_end_value_changed);
3689 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3690 }
3692 /* Segments / Pie checkbox */
3693 {
3694 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3696 GtkTreeIter iter;
3697 gtk_list_store_append( model, &iter );
3698 gtk_list_store_set( model, &iter,
3699 0, _("Closed arc"),
3700 1, _("Switch to segment (closed shape with two radii)"),
3701 2, "circle_closed_arc",
3702 -1 );
3704 gtk_list_store_append( model, &iter );
3705 gtk_list_store_set( model, &iter,
3706 0, _("Open Arc"),
3707 1, _("Switch to arc (unclosed shape)"),
3708 2, "circle_open_arc",
3709 -1 );
3711 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
3712 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3713 g_object_set_data( holder, "open_action", act );
3715 ege_select_one_action_set_appearance( act, "full" );
3716 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3717 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3718 ege_select_one_action_set_icon_column( act, 2 );
3719 ege_select_one_action_set_tooltip_column( act, 1 );
3721 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
3722 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
3723 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
3724 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
3725 }
3727 /* Make Whole */
3728 {
3729 InkAction* inky = ink_action_new( "ArcResetAction",
3730 _("Make whole"),
3731 _("Make the shape a whole ellipse, not arc or segment"),
3732 "reset_circle",
3733 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3734 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
3735 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3736 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3737 g_object_set_data( holder, "make_whole", inky );
3738 }
3740 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
3741 // sensitivize make whole and open checkbox
3742 {
3743 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
3744 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
3745 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
3746 }
3749 sigc::connection *connection = new sigc::connection(
3750 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
3751 );
3752 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3753 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3754 }
3759 // toggle button callbacks and updaters
3761 //########################
3762 //## Dropper ##
3763 //########################
3765 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
3766 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
3767 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
3768 if ( set_action ) {
3769 if ( gtk_toggle_action_get_active( act ) ) {
3770 gtk_action_set_sensitive( set_action, TRUE );
3771 } else {
3772 gtk_action_set_sensitive( set_action, FALSE );
3773 }
3774 }
3776 spinbutton_defocus(GTK_OBJECT(tbl));
3777 }
3779 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
3780 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3781 spinbutton_defocus(GTK_OBJECT(tbl));
3782 }
3785 /**
3786 * Dropper auxiliary toolbar construction and setup.
3787 *
3788 * TODO: Would like to add swatch of current color.
3789 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3790 * can drag and drop places. Will provide a nice mixing palette.
3791 */
3792 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3793 {
3794 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
3796 {
3797 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
3798 _("Pick alpha"),
3799 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
3800 "color_alpha_get",
3801 Inkscape::ICON_SIZE_DECORATION );
3802 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3803 g_object_set_data( holder, "pick_action", act );
3804 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
3805 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
3806 }
3808 {
3809 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
3810 _("Set alpha"),
3811 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
3812 "color_alpha_set",
3813 Inkscape::ICON_SIZE_DECORATION );
3814 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3815 g_object_set_data( holder, "set_action", act );
3816 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
3817 // make sure it's disabled if we're not picking alpha
3818 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
3819 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
3820 }
3821 }
3824 //########################
3825 //## Text Toolbox ##
3826 //########################
3827 /*
3828 static void
3829 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3830 {
3831 //Call back for letter sizing spinbutton
3832 }
3834 static void
3835 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3836 {
3837 //Call back for line height spinbutton
3838 }
3840 static void
3841 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3842 {
3843 //Call back for horizontal kerning spinbutton
3844 }
3846 static void
3847 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3848 {
3849 //Call back for vertical kerning spinbutton
3850 }
3852 static void
3853 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3854 {
3855 //Call back for letter rotation spinbutton
3856 }*/
3858 namespace {
3860 bool visible = false;
3862 void
3863 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
3864 {
3865 SPStyle *query =
3866 sp_style_new (SP_ACTIVE_DOCUMENT);
3868 int result_family =
3869 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3871 int result_style =
3872 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3874 int result_numbers =
3875 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3877 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3879 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3880 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3881 {
3882 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3884 if (repr)
3885 {
3886 sp_style_read_from_repr (query, repr);
3887 }
3888 else
3889 {
3890 return;
3891 }
3892 }
3894 if (query->text)
3895 {
3896 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3897 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3898 gtk_entry_set_text (GTK_ENTRY (entry), "");
3900 } else if (query->text->font_family.value) {
3902 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3903 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3905 Gtk::TreePath path;
3906 try {
3907 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3908 } catch (...) {
3909 return;
3910 }
3912 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3913 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3915 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3917 gtk_tree_selection_select_path (tselection, path.gobj());
3918 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3920 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3921 }
3923 //Size
3924 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3925 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3926 g_object_set_data (tbl, "size-block", gpointer(1));
3927 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3928 g_object_set_data (tbl, "size-block", gpointer(0));
3929 free (str);
3931 //Anchor
3932 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3933 {
3934 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3935 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3936 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3937 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3938 }
3939 else
3940 {
3941 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3942 {
3943 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3944 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3945 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3946 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3947 }
3948 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3949 {
3950 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3951 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3952 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3953 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3954 }
3955 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3956 {
3957 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3958 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3959 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3960 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3961 }
3962 }
3964 //Style
3965 {
3966 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3968 gboolean active = gtk_toggle_button_get_active (button);
3969 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3971 if (active != check)
3972 {
3973 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3974 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3975 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3976 }
3977 }
3979 {
3980 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3982 gboolean active = gtk_toggle_button_get_active (button);
3983 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3985 if (active != check)
3986 {
3987 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3988 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3989 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3990 }
3991 }
3993 //Orientation
3994 //locking both buttons, changing one affect all group (both)
3995 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3996 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3998 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3999 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
4001 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
4002 {
4003 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4004 }
4005 else
4006 {
4007 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
4008 }
4009 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4010 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
4011 }
4013 sp_style_unref(query);
4014 }
4016 void
4017 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
4018 {
4019 sp_text_toolbox_selection_changed (selection, tbl);
4020 }
4022 void
4023 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4024 {
4025 sp_text_toolbox_selection_changed (NULL, tbl);
4026 }
4028 void
4029 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4030 GObject *tbl)
4031 {
4032 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4033 GtkTreeModel *model = 0;
4034 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4035 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4036 GtkTreeIter iter;
4037 char *family = 0;
4039 (void)popdown;
4041 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4042 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4044 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
4045 return;
4046 }
4048 gtk_tree_model_get (model, &iter, 0, &family, -1);
4050 if (g_object_get_data (G_OBJECT (selection), "block"))
4051 {
4052 gtk_entry_set_text (GTK_ENTRY (entry), family);
4053 return;
4054 }
4056 gtk_entry_set_text (GTK_ENTRY (entry), family);
4058 SPStyle *query =
4059 sp_style_new (SP_ACTIVE_DOCUMENT);
4061 int result_numbers =
4062 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4064 SPCSSAttr *css = sp_repr_css_attr_new ();
4065 sp_repr_css_set_property (css, "font-family", family);
4067 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4068 if (result_numbers == QUERY_STYLE_NOTHING)
4069 {
4070 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4071 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
4072 }
4073 else
4074 {
4075 sp_desktop_set_style (desktop, css, true, true);
4076 }
4078 sp_style_unref(query);
4080 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4081 _("Text: Change font family"));
4082 sp_repr_css_attr_unref (css);
4083 free (family);
4084 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4086 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4087 }
4089 void
4090 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
4091 GObject *tbl)
4092 {
4093 const char *family = gtk_entry_get_text (entry);
4095 try {
4096 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
4097 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4098 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4099 gtk_tree_selection_select_path (selection, path.gobj());
4100 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4101 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4102 } catch (...) {
4103 if (family && strlen (family))
4104 {
4105 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4106 }
4107 }
4108 }
4110 void
4111 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
4112 gpointer data)
4113 {
4114 if (g_object_get_data (G_OBJECT (button), "block")) return;
4115 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
4116 int prop = GPOINTER_TO_INT(data);
4118 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4119 SPCSSAttr *css = sp_repr_css_attr_new ();
4121 switch (prop)
4122 {
4123 case 0:
4124 {
4125 sp_repr_css_set_property (css, "text-anchor", "start");
4126 sp_repr_css_set_property (css, "text-align", "start");
4127 break;
4128 }
4129 case 1:
4130 {
4131 sp_repr_css_set_property (css, "text-anchor", "middle");
4132 sp_repr_css_set_property (css, "text-align", "center");
4133 break;
4134 }
4136 case 2:
4137 {
4138 sp_repr_css_set_property (css, "text-anchor", "end");
4139 sp_repr_css_set_property (css, "text-align", "end");
4140 break;
4141 }
4143 case 3:
4144 {
4145 sp_repr_css_set_property (css, "text-anchor", "start");
4146 sp_repr_css_set_property (css, "text-align", "justify");
4147 break;
4148 }
4149 }
4151 SPStyle *query =
4152 sp_style_new (SP_ACTIVE_DOCUMENT);
4153 int result_numbers =
4154 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4156 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4157 if (result_numbers == QUERY_STYLE_NOTHING)
4158 {
4159 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4160 }
4162 sp_style_unref(query);
4164 sp_desktop_set_style (desktop, css, true, true);
4165 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4166 _("Text: Change alignment"));
4167 sp_repr_css_attr_unref (css);
4169 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4170 }
4172 void
4173 sp_text_toolbox_style_toggled (GtkToggleButton *button,
4174 gpointer data)
4175 {
4176 if (g_object_get_data (G_OBJECT (button), "block")) return;
4178 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4179 SPCSSAttr *css = sp_repr_css_attr_new ();
4180 int prop = GPOINTER_TO_INT(data);
4181 bool active = gtk_toggle_button_get_active (button);
4184 switch (prop)
4185 {
4186 case 0:
4187 {
4188 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
4189 break;
4190 }
4192 case 1:
4193 {
4194 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
4195 break;
4196 }
4197 }
4199 SPStyle *query =
4200 sp_style_new (SP_ACTIVE_DOCUMENT);
4201 int result_numbers =
4202 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4204 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4205 if (result_numbers == QUERY_STYLE_NOTHING)
4206 {
4207 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4208 }
4210 sp_style_unref(query);
4212 sp_desktop_set_style (desktop, css, true, true);
4213 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4214 _("Text: Change font style"));
4215 sp_repr_css_attr_unref (css);
4217 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4218 }
4220 void
4221 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
4222 gpointer data)
4223 {
4224 if (g_object_get_data (G_OBJECT (button), "block")) {
4225 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4226 return;
4227 }
4229 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4230 SPCSSAttr *css = sp_repr_css_attr_new ();
4231 int prop = GPOINTER_TO_INT(data);
4233 switch (prop)
4234 {
4235 case 0:
4236 {
4237 sp_repr_css_set_property (css, "writing-mode", "lr");
4238 break;
4239 }
4241 case 1:
4242 {
4243 sp_repr_css_set_property (css, "writing-mode", "tb");
4244 break;
4245 }
4246 }
4248 SPStyle *query =
4249 sp_style_new (SP_ACTIVE_DOCUMENT);
4250 int result_numbers =
4251 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4253 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4254 if (result_numbers == QUERY_STYLE_NOTHING)
4255 {
4256 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4257 }
4259 sp_desktop_set_style (desktop, css, true, true);
4260 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4261 _("Text: Change orientation"));
4262 sp_repr_css_attr_unref (css);
4264 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4265 }
4267 gboolean
4268 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, gpointer /*data*/)
4269 {
4270 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4271 if (!desktop) return FALSE;
4273 switch (get_group0_keyval (event)) {
4274 case GDK_Escape: // defocus
4275 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4276 return TRUE; // I consumed the event
4277 break;
4278 case GDK_Return: // defocus
4279 case GDK_KP_Enter:
4280 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4281 return TRUE; // I consumed the event
4282 break;
4283 }
4284 return FALSE;
4285 }
4287 gboolean
4288 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4289 {
4290 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4291 if (!desktop) return FALSE;
4293 switch (get_group0_keyval (event)) {
4294 case GDK_Escape: // defocus
4295 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4296 sp_text_toolbox_selection_changed (NULL, tbl); // update
4297 return TRUE; // I consumed the event
4298 break;
4299 }
4300 return FALSE;
4301 }
4303 gboolean
4304 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
4305 {
4306 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4307 if (!desktop) return FALSE;
4309 switch (get_group0_keyval (event)) {
4310 case GDK_KP_Enter:
4311 case GDK_Return:
4312 case GDK_Escape: // defocus
4313 gtk_widget_hide (w);
4314 visible = false;
4315 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4316 return TRUE; // I consumed the event
4317 break;
4318 }
4319 return FALSE;
4320 }
4323 void
4324 sp_text_toolbox_size_changed (GtkComboBox *cbox,
4325 GObject *tbl)
4326 {
4327 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4329 if (g_object_get_data (tbl, "size-block")) return;
4331 #if GTK_CHECK_VERSION(2,6,0)
4332 char *text = gtk_combo_box_get_active_text (cbox);
4333 #else // GTK_CHECK_VERSION(2,6,0)
4334 GtkTreeModel *model = gtk_combo_box_get_model (cbox);
4335 GtkTreeIter iter;
4336 char *text = NULL;
4338 if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
4339 gtk_tree_model_get (model, &iter, 0, &text, -1);
4340 #endif // GTK_CHECK_VERSION(2,6,0)
4342 SPCSSAttr *css = sp_repr_css_attr_new ();
4343 sp_repr_css_set_property (css, "font-size", text);
4344 free (text);
4346 SPStyle *query =
4347 sp_style_new (SP_ACTIVE_DOCUMENT);
4348 int result_numbers =
4349 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4351 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4352 if (result_numbers == QUERY_STYLE_NOTHING)
4353 {
4354 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4355 }
4357 sp_style_unref(query);
4359 sp_desktop_set_style (desktop, css, true, true);
4360 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
4361 _("Text: Change font size"));
4362 sp_repr_css_attr_unref (css);
4365 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
4366 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4367 }
4369 void
4370 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
4371 GObject *tbl)
4372 {
4373 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4374 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4375 int x, y;
4377 if (!visible)
4378 {
4379 gdk_window_get_origin (widget->window, &x, &y);
4380 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
4381 gtk_widget_show_all (popdown);
4383 gdk_pointer_grab (widget->window, TRUE,
4384 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
4385 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
4386 GDK_POINTER_MOTION_MASK),
4387 NULL, NULL, GDK_CURRENT_TIME);
4389 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
4391 visible = true;
4392 }
4393 else
4394 {
4395 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4396 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4397 gtk_widget_hide (popdown);
4398 visible = false;
4399 }
4400 }
4402 gboolean
4403 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
4404 GdkEventFocus */*event*/,
4405 GObject */*tbl*/)
4406 {
4407 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
4408 return FALSE;
4409 }
4411 gboolean
4412 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
4413 GdkEventFocus */*event*/,
4414 GObject */*tbl*/)
4415 {
4416 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4418 gtk_widget_hide (popdown);
4419 visible = false;
4420 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4421 return TRUE;
4422 }
4424 void
4425 cell_data_func (GtkTreeViewColumn */*column*/,
4426 GtkCellRenderer *cell,
4427 GtkTreeModel *tree_model,
4428 GtkTreeIter *iter,
4429 gpointer /*data*/)
4430 {
4431 char *family,
4432 *family_escaped,
4433 *sample_escaped;
4435 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
4437 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
4439 family_escaped = g_markup_escape_text (family, -1);
4440 sample_escaped = g_markup_escape_text (sample, -1);
4442 std::stringstream markup;
4443 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
4444 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
4446 free (family);
4447 free (family_escaped);
4448 free (sample_escaped);
4449 }
4451 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
4452 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
4453 if (completion) {
4454 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
4455 g_object_unref (completion);
4456 }
4457 }
4459 GtkWidget*
4460 sp_text_toolbox_new (SPDesktop *desktop)
4461 {
4462 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
4464 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4465 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4467 GtkTooltips *tt = gtk_tooltips_new();
4468 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4470 ////////////Family
4471 //Window
4472 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4473 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4475 //Entry
4476 GtkWidget *entry = gtk_entry_new ();
4477 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4478 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4479 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4480 gtk_entry_completion_set_text_column (completion, 0);
4481 gtk_entry_completion_set_minimum_key_length (completion, 1);
4482 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4483 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4484 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4485 aux_toolbox_space (tbl, 1);
4486 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
4487 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
4489 //Button
4490 GtkWidget *button = gtk_button_new ();
4491 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
4492 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
4494 //Popdown
4495 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
4496 GtkWidget *treeview = gtk_tree_view_new ();
4498 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4499 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
4500 gtk_tree_view_column_pack_start (column, cell, FALSE);
4501 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
4502 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
4503 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4505 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
4506 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
4507 #if GTK_CHECK_VERSION(2,6,0)
4508 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
4509 #endif // GTK_CHECK_VERSION(2,6,0)
4511 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
4513 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
4514 gtk_container_add (GTK_CONTAINER (sw), treeview);
4516 gtk_container_add (GTK_CONTAINER (window), sw);
4517 gtk_widget_set_size_request (window, 300, 450);
4519 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
4520 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
4521 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
4523 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
4525 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
4526 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
4528 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
4529 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
4531 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
4532 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
4533 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
4534 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
4535 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
4537 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
4538 aux_toolbox_space (tbl, 1);
4539 GtkWidget *box = gtk_event_box_new ();
4540 gtk_container_add (GTK_CONTAINER (box), image);
4541 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
4542 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
4543 GtkTooltips *tooltips = gtk_tooltips_new ();
4544 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
4545 gtk_widget_hide (GTK_WIDGET (box));
4546 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
4548 ////////////Size
4549 const char *sizes[] = {
4550 "4", "6", "8", "9", "10", "11", "12", "13", "14",
4551 "16", "18", "20", "22", "24", "28",
4552 "32", "36", "40", "48", "56", "64", "72", "144"
4553 };
4555 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
4556 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
4557 gtk_widget_set_size_request (cbox, 80, -1);
4558 aux_toolbox_space (tbl, 1);
4559 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
4560 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
4561 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
4562 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
4564 //spacer
4565 aux_toolbox_space (tbl, 4);
4566 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4568 ////////////Text anchor
4569 GtkWidget *group = gtk_radio_button_new (NULL);
4570 GtkWidget *row = gtk_hbox_new (FALSE, 4);
4571 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
4573 // left
4574 GtkWidget *rbutton = group;
4575 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4576 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4577 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4579 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4580 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
4581 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
4582 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
4584 // center
4585 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4586 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4587 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
4588 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4590 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4591 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
4592 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
4593 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
4595 // right
4596 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4597 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4598 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4599 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4601 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4602 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
4603 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
4604 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
4606 // fill
4607 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4608 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4609 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
4610 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4612 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4613 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
4614 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
4615 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
4617 aux_toolbox_space (tbl, 1);
4618 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4620 //spacer
4621 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4623 ////////////Text style
4624 row = gtk_hbox_new (FALSE, 4);
4626 // bold
4627 rbutton = gtk_toggle_button_new ();
4628 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4629 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
4630 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4631 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
4633 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4634 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
4635 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
4637 // italic
4638 rbutton = gtk_toggle_button_new ();
4639 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4640 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
4641 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4642 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
4644 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4645 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
4646 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
4648 aux_toolbox_space (tbl, 1);
4649 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4651 //spacer
4652 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4654 ////////////Text orientation
4655 group = gtk_radio_button_new (NULL);
4656 row = gtk_hbox_new (FALSE, 4);
4657 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4659 // horizontal
4660 rbutton = group;
4661 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4662 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4663 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4664 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4666 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4667 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4668 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4670 // vertical
4671 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4672 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4673 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4674 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4675 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4677 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4678 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4679 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4680 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4683 //watch selection
4684 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4686 sigc::connection *c_selection_changed =
4687 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4688 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4689 pool->add_connection ("selection-changed", c_selection_changed);
4691 sigc::connection *c_selection_modified =
4692 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4693 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4694 pool->add_connection ("selection-modified", c_selection_modified);
4696 sigc::connection *c_subselection_changed =
4697 new sigc::connection (desktop->connectToolSubselectionChanged
4698 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4699 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4701 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4704 #if 0
4705 // horizontal
4706 {
4707 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
4708 GtkWidget *b = group = gtk_radio_button_new (NULL);
4709 gtk_container_add (GTK_CONTAINER (b), px);
4710 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
4711 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4712 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4713 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4714 }
4716 // vertical
4717 {
4718 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
4719 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4720 gtk_container_add (GTK_CONTAINER (b), px);
4721 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
4722 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4723 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4724 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4725 }
4727 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4729 // letter spacing
4730 {
4731 {
4732 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
4733 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4734 gtk_container_add (GTK_CONTAINER (hb), image);
4735 gtk_widget_show(image);
4736 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4737 }
4739 {
4740 GtkWidget *hb = sp_tb_spinbutton((""), _("Spacing between letters"),
4741 "tools.text", "letter_spacing", 0.0,
4742 us, tbl, FALSE, NULL,
4743 -1000.0, 1000.0, 0.1, 0.1,
4744 sp_text_letter_changed, 0.1, 1);
4745 gtk_widget_set_size_request (hb, 45, 6);
4746 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4747 }
4748 }
4750 // line spacing
4751 {
4752 {
4753 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
4754 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4755 gtk_container_add (GTK_CONTAINER (hb), image);
4756 gtk_widget_show(image);
4757 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4758 }
4760 {
4761 GtkWidget *hb = sp_tb_spinbutton((""), _("Spacing between lines"),
4762 "tools.text", "line_spacing", 0,
4763 us, tbl, FALSE, NULL,
4764 -1000.0, 1000.0, 0.1, 0.1,
4765 sp_text_line_changed, 0.1, 1);
4766 gtk_widget_set_size_request (hb, 45, 0);
4767 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
4768 }
4769 }
4771 {
4772 // horizontal kerning/vertical kerning units menu: create
4773 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
4774 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
4775 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
4777 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4779 // horizontal kerning
4780 {
4781 {
4782 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
4783 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4784 gtk_container_add (GTK_CONTAINER (hb), image);
4785 gtk_widget_show(image);
4786 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4787 }
4789 {
4790 GtkWidget *hb = sp_tb_spinbutton((""), _("Horizontal kerning"),
4791 "tools.text", "horizontal_kerning", 0,
4792 us, tbl, FALSE, NULL,
4793 -100.00, 100.00, 0.01, 0.1,
4794 sp_text_horiz_kern_changed);
4795 gtk_widget_set_size_request (hb, 45, 0);
4796 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4797 }
4798 }
4800 // vertical kerning
4801 {
4802 {
4803 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
4804 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4805 gtk_container_add (GTK_CONTAINER (hb), image);
4806 gtk_widget_show(image);
4807 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4808 }
4810 {
4811 GtkWidget *hb = sp_tb_spinbutton((""), _("Vertical kerning"),
4812 "tools.text", "vertical_kerning", 0,
4813 us, tbl, FALSE, NULL,
4814 -100.00, 100.00, 0.01, 0.1,
4815 sp_text_vert_kern_changed);
4816 gtk_widget_set_size_request (hb, 45, 0);
4817 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
4818 }
4819 }
4821 // add the units menu
4822 gtk_widget_show(us);
4823 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
4824 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
4825 }
4827 // letter rotation
4828 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4829 {
4830 {
4831 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
4832 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4833 gtk_container_add (GTK_CONTAINER (hb), image);
4834 gtk_widget_show(image);
4835 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4836 }
4837 {
4838 GtkWidget *hb = sp_tb_spinbutton((""), _("Letter rotation"),
4839 "tools.text", "letter_rotation", 0,
4840 us, tbl, FALSE, NULL,
4841 -180.0, 180.0, 0.1, 0.1,
4842 sp_text_letter_rotation_changed, 0.1, 1);
4843 gtk_widget_set_size_request (hb, 45, 0);
4844 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4845 }
4846 // rotation degree label
4847 {
4848 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4849 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4850 }
4851 }
4853 // Remove Manual Kerns
4854 {
4855 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4856 GtkWidget *button = gtk_button_new ();
4857 gtk_container_add (GTK_CONTAINER (button), px);
4858 gtk_widget_show(button);
4859 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4860 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4861 gtk_widget_set_sensitive(button, TRUE);
4862 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4863 }
4864 #endif
4866 gtk_widget_show_all (tbl);
4867 return tbl;
4869 } // end of sp_text_toolbox_new()
4871 }//<unnamed> namespace
4874 //#########################
4875 //## Connector ##
4876 //#########################
4878 static void sp_connector_path_set_avoid(void)
4879 {
4880 cc_selection_set_avoid(true);
4881 }
4884 static void sp_connector_path_set_ignore(void)
4885 {
4886 cc_selection_set_avoid(false);
4887 }
4891 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4892 {
4893 // quit if run by the _changed callbacks
4894 if (g_object_get_data( tbl, "freeze" )) {
4895 return;
4896 }
4898 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4899 SPDocument *doc = sp_desktop_document(desktop);
4901 if (!sp_document_get_undo_sensitive(doc))
4902 {
4903 return;
4904 }
4906 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4908 if ( repr->attribute("inkscape:connector-spacing") ) {
4909 gdouble priorValue = gtk_adjustment_get_value(adj);
4910 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4911 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4912 return;
4913 }
4914 } else if ( adj->value == defaultConnSpacing ) {
4915 return;
4916 }
4918 // in turn, prevent callbacks from responding
4919 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4921 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4922 SP_OBJECT(desktop->namedview)->updateRepr();
4924 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4925 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4926 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4927 NR::Matrix m = NR::identity();
4928 avoid_item_move(&m, item);
4929 }
4931 if (items) {
4932 g_slist_free(items);
4933 }
4935 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4936 _("Change connector spacing"));
4938 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4940 spinbutton_defocus(GTK_OBJECT(tbl));
4941 }
4943 static void sp_connector_graph_layout(void)
4944 {
4945 if (!SP_ACTIVE_DESKTOP) return;
4947 // hack for clones, see comment in align-and-distribute.cpp
4948 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4949 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4951 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4953 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4955 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4956 }
4958 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4959 {
4960 if ( gtk_toggle_action_get_active( act ) ) {
4961 prefs_set_string_attribute("tools.connector", "directedlayout",
4962 "true");
4963 } else {
4964 prefs_set_string_attribute("tools.connector", "directedlayout",
4965 "false");
4966 }
4967 }
4969 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4970 {
4971 if ( gtk_toggle_action_get_active( act ) ) {
4972 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4973 "true");
4974 } else {
4975 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4976 "false");
4977 }
4978 }
4981 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4982 {
4983 prefs_set_double_attribute("tools.connector", "length", adj->value);
4984 spinbutton_defocus(GTK_OBJECT(tbl));
4985 }
4987 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4988 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
4989 bool /*is_interactive*/, gpointer data)
4990 {
4991 GtkWidget *tbl = GTK_WIDGET(data);
4993 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4994 return;
4995 }
4996 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4997 return;
4998 }
5000 GtkAdjustment *adj = (GtkAdjustment*)
5001 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
5002 gdouble spacing = defaultConnSpacing;
5003 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
5005 gtk_adjustment_set_value(adj, spacing);
5006 }
5009 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
5010 NULL, /* child_added */
5011 NULL, /* child_removed */
5012 connector_tb_event_attr_changed,
5013 NULL, /* content_changed */
5014 NULL /* order_changed */
5015 };
5018 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
5019 {
5020 {
5021 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
5022 _("Avoid"),
5023 _("Make connectors avoid selected objects"),
5024 "connector_avoid",
5025 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5026 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
5027 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5028 }
5030 {
5031 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
5032 _("Ignore"),
5033 _("Make connectors ignore selected objects"),
5034 "connector_ignore",
5035 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5036 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
5037 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5038 }
5040 EgeAdjustmentAction* eact = 0;
5042 // Spacing spinbox
5043 eact = create_adjustment_action( "ConnectorSpacingAction",
5044 _("Connector Spacing"), _("Spacing:"),
5045 _("The amount of space left around objects by auto-routing connectors"),
5046 "tools.connector", "spacing", defaultConnSpacing,
5047 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
5048 0, 100, 1.0, 10.0,
5049 0, 0, 0,
5050 connector_spacing_changed, 1, 0 );
5051 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5053 // Graph (connector network) layout
5054 {
5055 InkAction* inky = ink_action_new( "ConnectorGraphAction",
5056 _("Graph"),
5057 _("Nicely arrange selected connector network"),
5058 "graph_layout",
5059 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5060 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
5061 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5062 }
5064 // Default connector length spinbox
5065 eact = create_adjustment_action( "ConnectorLengthAction",
5066 _("Connector Length"), _("Length:"),
5067 _("Ideal length for connectors when layout is applied"),
5068 "tools.connector", "length", 100,
5069 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
5070 10, 1000, 10.0, 100.0,
5071 0, 0, 0,
5072 connector_length_changed, 1, 0 );
5073 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5076 // Directed edges toggle button
5077 {
5078 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
5079 _("Downwards"),
5080 _("Make connectors with end-markers (arrows) point downwards"),
5081 "directed_graph",
5082 Inkscape::ICON_SIZE_DECORATION );
5083 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5085 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
5086 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5087 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5089 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
5090 }
5092 // Avoid overlaps toggle button
5093 {
5094 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
5095 _("Remove overlaps"),
5096 _("Do not allow overlapping shapes"),
5097 "remove_overlaps",
5098 Inkscape::ICON_SIZE_DECORATION );
5099 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5101 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
5102 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5103 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5105 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
5106 }
5108 // Code to watch for changes to the connector-spacing attribute in
5109 // the XML.
5110 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5111 g_assert(repr != NULL);
5113 purge_repr_listener( holder, holder );
5115 if (repr) {
5116 g_object_set_data( holder, "repr", repr );
5117 Inkscape::GC::anchor(repr);
5118 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
5119 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
5120 }
5121 } // end of sp_connector_toolbox_prep()
5124 //#########################
5125 //## Paintbucket ##
5126 //#########################
5128 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
5129 {
5130 gint channels = ege_select_one_action_get_active( act );
5131 flood_channels_set_channels( channels );
5132 }
5134 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
5135 {
5136 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
5137 }
5139 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
5140 {
5141 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
5142 }
5144 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
5145 {
5146 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
5147 SPUnit const *unit = tracker->getActiveUnit();
5149 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
5151 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
5152 }
5154 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
5155 {
5156 // FIXME: make defaults settable via Inkscape Options
5157 struct KeyValue {
5158 char const *key;
5159 double value;
5160 } const key_values[] = {
5161 {"threshold", 15},
5162 {"offset", 0.0}
5163 };
5165 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
5166 KeyValue const &kv = key_values[i];
5167 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
5168 if ( adj ) {
5169 gtk_adjustment_set_value(adj, kv.value);
5170 }
5171 }
5173 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
5174 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
5175 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
5176 ege_select_one_action_set_active( autogap_action, 0 );
5177 }
5179 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5180 {
5181 EgeAdjustmentAction* eact = 0;
5183 {
5184 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5186 GList* items = 0;
5187 gint count = 0;
5188 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
5189 {
5190 GtkTreeIter iter;
5191 gtk_list_store_append( model, &iter );
5192 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5193 count++;
5194 }
5195 g_list_free( items );
5196 items = 0;
5197 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
5198 g_object_set( act1, "short_label", _("Fill by:"), NULL );
5199 ege_select_one_action_set_appearance( act1, "compact" );
5200 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
5201 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
5202 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
5203 g_object_set_data( holder, "channels_action", act1 );
5204 }
5206 // Spacing spinbox
5207 {
5208 eact = create_adjustment_action(
5209 "ThresholdAction",
5210 _("Fill Threshold"), _("Threshold:"),
5211 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
5212 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
5213 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
5214 0, 0, 0,
5215 paintbucket_threshold_changed, 1, 0 );
5217 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5218 }
5220 // Create the units menu.
5221 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
5222 tracker->setActiveUnit(sp_unit_get_by_abbreviation(prefs_get_string_attribute("tools.paintbucket", "offsetunits")));
5223 g_object_set_data( holder, "tracker", tracker );
5224 {
5225 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
5226 gtk_action_group_add_action( mainActions, act );
5227 }
5229 // Offset spinbox
5230 {
5231 eact = create_adjustment_action(
5232 "OffsetAction",
5233 _("Grow/shrink by"), _("Grow/shrink by:"),
5234 _("The amount to grow (positive) or shrink (negative) the created fill path"),
5235 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
5236 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
5237 0, 0, 0,
5238 paintbucket_offset_changed, 1, 2);
5239 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
5241 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5242 }
5244 /* Auto Gap */
5245 {
5246 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5248 GList* items = 0;
5249 gint count = 0;
5250 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
5251 {
5252 GtkTreeIter iter;
5253 gtk_list_store_append( model, &iter );
5254 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5255 count++;
5256 }
5257 g_list_free( items );
5258 items = 0;
5259 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
5260 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
5261 ege_select_one_action_set_appearance( act2, "compact" );
5262 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
5263 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
5264 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
5265 g_object_set_data( holder, "autogap_action", act2 );
5266 }
5268 /* Reset */
5269 {
5270 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
5271 _("Defaults"),
5272 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
5273 GTK_STOCK_CLEAR );
5274 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
5275 gtk_action_group_add_action( mainActions, act );
5276 gtk_action_set_sensitive( act, TRUE );
5277 }
5279 }
5281 /*
5282 Local Variables:
5283 mode:c++
5284 c-file-style:"stroustrup"
5285 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
5286 indent-tabs-mode:nil
5287 fill-column:99
5288 End:
5289 */
5290 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :