a4d24203f95bfae6fe2ab1f8adba82ba69379c5b
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 "document-private.h"
76 #include "desktop-style.h"
77 #include "../libnrtype/font-lister.h"
78 #include "../connection-pool.h"
79 #include "../prefs-utils.h"
80 #include "../inkscape-stock.h"
81 #include "icon.h"
82 #include "graphlayout/graphlayout.h"
84 #include "mod360.h"
86 #include "toolbox.h"
88 #include "flood-context.h"
90 #include "ink-action.h"
91 #include "ege-adjustment-action.h"
92 #include "ege-output-action.h"
93 #include "ege-select-one-action.h"
94 #include "helper/unit-tracker.h"
96 using Inkscape::UnitTracker;
98 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
99 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
101 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
102 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
103 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
104 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
105 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
114 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
120 static struct {
121 gchar const *type_name;
122 gchar const *data_name;
123 sp_verb_t verb;
124 sp_verb_t doubleclick_verb;
125 } const tools[] = {
126 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
127 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
128 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
129 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
130 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
131 // { "SP3DBoxContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
132 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
133 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
134 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
135 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
136 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
137 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
138 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
139 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
140 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
141 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
142 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
143 { NULL, NULL, 0, 0 }
144 };
146 static struct {
147 gchar const *type_name;
148 gchar const *data_name;
149 GtkWidget *(*create_func)(SPDesktop *desktop);
150 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
151 gchar const *ui_name;
152 gint swatch_verb_id;
153 gchar const *swatch_tool;
154 gchar const *swatch_tip;
155 } const aux_toolboxes[] = {
156 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
157 SP_VERB_INVALID, 0, 0},
158 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
159 SP_VERB_INVALID, 0, 0},
160 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
161 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", _("Color/opacity used for color tweaking")},
162 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
163 SP_VERB_INVALID, 0, 0},
164 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
165 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
166 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
167 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
168 { "SP3DBoxContext", "3dbox_toolbox", 0, sp_3dbox_toolbox_prep, "3DBoxToolbar",
169 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
170 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
171 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
172 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
173 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
174 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
175 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
176 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
177 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
178 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
179 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
180 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
181 SP_VERB_INVALID, 0, 0},
182 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
183 SP_VERB_INVALID, 0, 0},
184 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
185 SP_VERB_INVALID, 0, 0},
186 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
187 SP_VERB_INVALID, 0, 0},
188 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
189 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
190 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
191 };
194 static gchar const * ui_descr =
195 "<ui>"
196 " <toolbar name='SelectToolbar'>"
197 " <toolitem action='EditSelectAll' />"
198 " <toolitem action='EditSelectAllInAllLayers' />"
199 " <toolitem action='EditDeselect' />"
200 " <separator />"
201 " <toolitem action='ObjectRotate90CCW' />"
202 " <toolitem action='ObjectRotate90' />"
203 " <toolitem action='ObjectFlipHorizontally' />"
204 " <toolitem action='ObjectFlipVertically' />"
205 " <separator />"
206 " <toolitem action='SelectionToBack' />"
207 " <toolitem action='SelectionLower' />"
208 " <toolitem action='SelectionRaise' />"
209 " <toolitem action='SelectionToFront' />"
210 " <separator />"
211 " <toolitem action='XAction' />"
212 " <toolitem action='YAction' />"
213 " <toolitem action='WidthAction' />"
214 " <toolitem action='LockAction' />"
215 " <toolitem action='HeightAction' />"
216 " <toolitem action='UnitsAction' />"
217 " <separator />"
218 " <toolitem action='transform_affect_label' />"
219 " <toolitem action='transform_stroke' />"
220 " <toolitem action='transform_corners' />"
221 " <toolitem action='transform_gradient' />"
222 " <toolitem action='transform_pattern' />"
223 " </toolbar>"
225 " <toolbar name='NodeToolbar'>"
226 " <toolitem action='NodeInsertAction' />"
227 " <toolitem action='NodeDeleteAction' />"
228 " <separator />"
229 " <toolitem action='NodeJoinAction' />"
230 " <toolitem action='NodeJoinSegmentAction' />"
231 " <toolitem action='NodeDeleteSegmentAction' />"
232 " <toolitem action='NodeBreakAction' />"
233 " <separator />"
234 " <toolitem action='NodeCuspAction' />"
235 " <toolitem action='NodeSmoothAction' />"
236 " <toolitem action='NodeSymmetricAction' />"
237 " <separator />"
238 " <toolitem action='NodeLineAction' />"
239 " <toolitem action='NodeCurveAction' />"
240 " <separator />"
241 " <toolitem action='ObjectToPath' />"
242 " <toolitem action='StrokeToPath' />"
243 " <separator />"
244 " <toolitem action='NodesShowHandlesAction' />"
245 " <separator />"
246 " <toolitem action='NodeXAction' />"
247 " <toolitem action='NodeYAction' />"
248 " </toolbar>"
250 " <toolbar name='TweakToolbar'>"
251 " <toolitem action='TweakWidthAction' />"
252 " <separator />"
253 " <toolitem action='TweakForceAction' />"
254 " <toolitem action='TweakPressureAction' />"
255 " <separator />"
256 " <toolitem action='TweakModeAction' />"
257 " <separator />"
258 " <toolitem action='TweakFidelityAction' />"
259 " <separator />"
260 " <toolitem action='TweakChannelsLabel' />"
261 " <toolitem action='TweakDoH' />"
262 " <toolitem action='TweakDoS' />"
263 " <toolitem action='TweakDoL' />"
264 " <toolitem action='TweakDoO' />"
265 " </toolbar>"
267 " <toolbar name='ZoomToolbar'>"
268 " <toolitem action='ZoomIn' />"
269 " <toolitem action='ZoomOut' />"
270 " <separator />"
271 " <toolitem action='Zoom1:0' />"
272 " <toolitem action='Zoom1:2' />"
273 " <toolitem action='Zoom2:1' />"
274 " <separator />"
275 " <toolitem action='ZoomSelection' />"
276 " <toolitem action='ZoomDrawing' />"
277 " <toolitem action='ZoomPage' />"
278 " <toolitem action='ZoomPageWidth' />"
279 " <separator />"
280 " <toolitem action='ZoomPrev' />"
281 " <toolitem action='ZoomNext' />"
282 " </toolbar>"
284 " <toolbar name='StarToolbar'>"
285 " <separator />"
286 " <toolitem action='StarStateAction' />"
287 " <separator />"
288 " <toolitem action='FlatAction' />"
289 " <separator />"
290 " <toolitem action='MagnitudeAction' />"
291 " <toolitem action='SpokeAction' />"
292 " <toolitem action='RoundednessAction' />"
293 " <toolitem action='RandomizationAction' />"
294 " <separator />"
295 " <toolitem action='StarResetAction' />"
296 " </toolbar>"
298 " <toolbar name='RectToolbar'>"
299 " <toolitem action='RectStateAction' />"
300 " <toolitem action='RectWidthAction' />"
301 " <toolitem action='RectHeightAction' />"
302 " <toolitem action='RadiusXAction' />"
303 " <toolitem action='RadiusYAction' />"
304 " <toolitem action='RectUnitsAction' />"
305 " <separator />"
306 " <toolitem action='RectResetAction' />"
307 " </toolbar>"
309 " <toolbar name='3DBoxToolbar'>"
310 " <toolitem action='3DBoxPosAngleXAction' />"
311 " <toolitem action='3DBoxVPXAction' />"
312 " <separator />"
313 " <toolitem action='3DBoxPosAngleYAction' />"
314 " <toolitem action='3DBoxVPYAction' />"
315 " <separator />"
316 " <toolitem action='3DBoxPosAngleZAction' />"
317 " <toolitem action='3DBoxVPZAction' />"
318 " <separator />"
319 " </toolbar>"
321 " <toolbar name='SpiralToolbar'>"
322 " <toolitem action='SpiralStateAction' />"
323 " <toolitem action='SpiralRevolutionAction' />"
324 " <toolitem action='SpiralExpansionAction' />"
325 " <toolitem action='SpiralT0Action' />"
326 " <separator />"
327 " <toolitem action='SpiralResetAction' />"
328 " </toolbar>"
330 " <toolbar name='PenToolbar'>"
331 " </toolbar>"
333 " <toolbar name='PencilToolbar'>"
334 " </toolbar>"
336 " <toolbar name='CalligraphyToolbar'>"
337 " <separator />"
338 " <toolitem action='CalligraphyWidthAction' />"
339 " <toolitem action='PressureAction' />"
340 " <toolitem action='TraceAction' />"
341 " <toolitem action='ThinningAction' />"
342 " <separator />"
343 " <toolitem action='AngleAction' />"
344 " <toolitem action='TiltAction' />"
345 " <toolitem action='FixationAction' />"
346 " <separator />"
347 " <toolitem action='CapRoundingAction' />"
348 " <separator />"
349 " <toolitem action='TremorAction' />"
350 " <toolitem action='WiggleAction' />"
351 " <toolitem action='MassAction' />"
352 " <separator />"
353 " <toolitem action='CalligraphyResetAction' />"
354 " </toolbar>"
356 " <toolbar name='ArcToolbar'>"
357 " <toolitem action='ArcStateAction' />"
358 " <separator />"
359 " <toolitem action='ArcStartAction' />"
360 " <toolitem action='ArcEndAction' />"
361 " <separator />"
362 " <toolitem action='ArcOpenAction' />"
363 " <separator />"
364 " <toolitem action='ArcResetAction' />"
365 " <separator />"
366 " </toolbar>"
368 " <toolbar name='PaintbucketToolbar'>"
369 " <toolitem action='ChannelsAction' />"
370 " <separator />"
371 " <toolitem action='ThresholdAction' />"
372 " <separator />"
373 " <toolitem action='OffsetAction' />"
374 " <toolitem action='PaintbucketUnitsAction' />"
375 " <separator />"
376 " <toolitem action='AutoGapAction' />"
377 " <separator />"
378 " <toolitem action='PaintbucketResetAction' />"
379 " </toolbar>"
381 " <toolbar name='DropperToolbar'>"
382 " <toolitem action='DropperPickAlphaAction' />"
383 " <toolitem action='DropperSetAlphaAction' />"
384 " </toolbar>"
386 " <toolbar name='ConnectorToolbar'>"
387 " <toolitem action='ConnectorAvoidAction' />"
388 " <toolitem action='ConnectorIgnoreAction' />"
389 " <toolitem action='ConnectorSpacingAction' />"
390 " <toolitem action='ConnectorGraphAction' />"
391 " <toolitem action='ConnectorLengthAction' />"
392 " <toolitem action='ConnectorDirectedAction' />"
393 " <toolitem action='ConnectorOverlapAction' />"
394 " </toolbar>"
396 "</ui>"
397 ;
399 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
401 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
403 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
404 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
406 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
407 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
409 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
410 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
412 /* Global text entry widgets necessary for update */
413 /* GtkWidget *dropper_rgb_entry,
414 *dropper_opacity_entry ; */
415 // should be made a private member once this is converted to class
417 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
418 connection->disconnect();
419 delete connection;
420 }
422 static void purge_repr_listener( GObject* obj, GObject* tbl )
423 {
424 (void)obj;
425 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
426 if (oldrepr) { // remove old listener
427 sp_repr_remove_listener_by_data(oldrepr, tbl);
428 Inkscape::GC::release(oldrepr);
429 oldrepr = 0;
430 g_object_set_data( tbl, "repr", NULL );
431 }
432 }
434 GtkWidget *
435 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
436 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
437 Inkscape::UI::View::View *view, GtkTooltips *tt)
438 {
439 SPAction *action = verb->get_action(view);
440 if (!action) return NULL;
442 SPAction *doubleclick_action;
443 if (doubleclick_verb)
444 doubleclick_action = doubleclick_verb->get_action(view);
445 else
446 doubleclick_action = NULL;
448 /* fixme: Handle sensitive/unsensitive */
449 /* fixme: Implement sp_button_new_from_action */
450 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
451 gtk_widget_show(b);
452 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
454 return b;
455 }
457 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
458 Inkscape::UI::View::View *view, GtkTooltips *tt)
459 {
460 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
461 }
463 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
464 Inkscape::UI::View::View *view, GtkTooltips *tt)
465 {
466 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
467 }
470 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
471 {
472 SPAction* targetAction = SP_ACTION(user_data);
473 if ( targetAction ) {
474 sp_action_perform( targetAction, NULL );
475 }
476 }
478 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
479 {
480 if ( data ) {
481 GtkAction* act = GTK_ACTION(data);
482 gtk_action_set_sensitive( act, sensitive );
483 }
484 }
486 static SPActionEventVector action_event_vector = {
487 {NULL},
488 NULL,
489 NULL,
490 sp_action_action_set_sensitive,
491 NULL,
492 NULL
493 };
495 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
496 {
497 GtkAction* act = 0;
499 SPAction* targetAction = verb->get_action(view);
500 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
501 act = GTK_ACTION(inky);
502 gtk_action_set_sensitive( act, targetAction->sensitive );
504 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
506 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
507 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
509 return act;
510 }
512 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
513 {
514 Inkscape::UI::View::View *view = desktop;
515 gint verbsToUse[] = {
516 // disabled until we have icons for them:
517 //find
518 //SP_VERB_EDIT_TILE,
519 //SP_VERB_EDIT_UNTILE,
520 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
521 SP_VERB_DIALOG_DISPLAY,
522 SP_VERB_DIALOG_FILL_STROKE,
523 SP_VERB_DIALOG_NAMEDVIEW,
524 SP_VERB_DIALOG_TEXT,
525 SP_VERB_DIALOG_XML_EDITOR,
526 SP_VERB_EDIT_CLONE,
527 SP_VERB_EDIT_COPY,
528 SP_VERB_EDIT_CUT,
529 SP_VERB_EDIT_DUPLICATE,
530 SP_VERB_EDIT_PASTE,
531 SP_VERB_EDIT_REDO,
532 SP_VERB_EDIT_UNDO,
533 SP_VERB_EDIT_UNLINK_CLONE,
534 SP_VERB_FILE_EXPORT,
535 SP_VERB_FILE_IMPORT,
536 SP_VERB_FILE_NEW,
537 SP_VERB_FILE_OPEN,
538 SP_VERB_FILE_PRINT,
539 SP_VERB_FILE_SAVE,
540 SP_VERB_OBJECT_TO_CURVE,
541 SP_VERB_SELECTION_GROUP,
542 SP_VERB_SELECTION_OUTLINE,
543 SP_VERB_SELECTION_UNGROUP,
544 SP_VERB_ZOOM_1_1,
545 SP_VERB_ZOOM_1_2,
546 SP_VERB_ZOOM_2_1,
547 SP_VERB_ZOOM_DRAWING,
548 SP_VERB_ZOOM_IN,
549 SP_VERB_ZOOM_NEXT,
550 SP_VERB_ZOOM_OUT,
551 SP_VERB_ZOOM_PAGE,
552 SP_VERB_ZOOM_PAGE_WIDTH,
553 SP_VERB_ZOOM_PREV,
554 SP_VERB_ZOOM_SELECTION,
555 };
557 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
558 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
560 static std::map<SPDesktop*, GtkActionGroup*> groups;
561 GtkActionGroup* mainActions = 0;
562 if ( groups.find(desktop) != groups.end() ) {
563 mainActions = groups[desktop];
564 }
566 if ( !mainActions ) {
567 mainActions = gtk_action_group_new("main");
568 groups[desktop] = mainActions;
569 }
571 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
572 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
573 if ( verb ) {
574 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
575 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
576 gtk_action_group_add_action( mainActions, act );
577 }
578 }
579 }
581 return mainActions;
582 }
585 GtkWidget *
586 sp_tool_toolbox_new()
587 {
588 GtkTooltips *tt = gtk_tooltips_new();
589 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
591 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
592 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
594 gtk_widget_set_sensitive(tb, FALSE);
596 GtkWidget *hb = gtk_handle_box_new();
597 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
598 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
599 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
601 gtk_container_add(GTK_CONTAINER(hb), tb);
602 gtk_widget_show(GTK_WIDGET(tb));
604 sigc::connection* conn = new sigc::connection;
605 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
607 return hb;
608 }
610 static void
611 aux_toolbox_attached(GtkHandleBox */*toolbox*/, GtkWidget *child)
612 {
613 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
614 gtk_widget_queue_resize(child);
615 }
617 static void
618 aux_toolbox_detached(GtkHandleBox */*toolbox*/, GtkWidget *child)
619 {
620 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
621 gtk_widget_queue_resize(child);
622 }
624 GtkWidget *
625 sp_aux_toolbox_new()
626 {
627 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
629 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
630 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
631 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
632 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
633 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
635 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
636 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
638 gtk_widget_set_sensitive(tb, FALSE);
640 GtkWidget *hb = gtk_handle_box_new();
641 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
642 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
643 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
645 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
646 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
648 gtk_container_add(GTK_CONTAINER(hb), tb);
649 gtk_widget_show(GTK_WIDGET(tb));
651 sigc::connection* conn = new sigc::connection;
652 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
654 return hb;
655 }
657 //####################################
658 //# Commands Bar
659 //####################################
661 GtkWidget *
662 sp_commands_toolbox_new()
663 {
664 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
666 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
667 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
668 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
669 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
670 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
672 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
673 gtk_widget_set_sensitive(tb, FALSE);
675 GtkWidget *hb = gtk_handle_box_new();
676 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
677 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
678 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
680 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
681 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
683 gtk_container_add(GTK_CONTAINER(hb), tb);
684 gtk_widget_show(GTK_WIDGET(tb));
686 sigc::connection* conn = new sigc::connection;
687 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
689 return hb;
690 }
692 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
693 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
694 gchar const *path, gchar const *data, gdouble def,
695 GtkWidget *focusTarget,
696 GtkWidget *us,
697 GObject *dataKludge,
698 gboolean altx, gchar const *altx_mark,
699 gdouble lower, gdouble upper, gdouble step, gdouble page,
700 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
701 void (*callback)(GtkAdjustment *, GObject *),
702 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
703 {
704 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
705 lower, upper, step, page, page ) );
706 if (us) {
707 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
708 }
710 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
712 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
713 if ( shortLabel ) {
714 g_object_set( act, "short_label", shortLabel, NULL );
715 }
717 if ( (descrCount > 0) && descrLabels && descrValues ) {
718 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
719 }
721 if ( focusTarget ) {
722 ege_adjustment_action_set_focuswidget( act, focusTarget );
723 }
725 if ( altx && altx_mark ) {
726 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
727 }
729 if ( dataKludge ) {
730 g_object_set_data( dataKludge, data, adj );
731 }
733 // Using a cast just to make sure we pass in the right kind of function pointer
734 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
736 return act;
737 }
740 //####################################
741 //# node editing callbacks
742 //####################################
744 /**
745 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
746 */
747 static ShapeEditor *get_current_shape_editor()
748 {
749 if (!SP_ACTIVE_DESKTOP) {
750 return NULL;
751 }
753 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
755 if (!SP_IS_NODE_CONTEXT(event_context)) {
756 return NULL;
757 }
759 return SP_NODE_CONTEXT(event_context)->shape_editor;
760 }
763 void
764 sp_node_path_edit_add(void)
765 {
766 ShapeEditor *shape_editor = get_current_shape_editor();
767 if (shape_editor) shape_editor->add_node();
768 }
770 void
771 sp_node_path_edit_delete(void)
772 {
773 ShapeEditor *shape_editor = get_current_shape_editor();
774 if (shape_editor) shape_editor->delete_nodes();
775 }
777 void
778 sp_node_path_edit_delete_segment(void)
779 {
780 ShapeEditor *shape_editor = get_current_shape_editor();
781 if (shape_editor) shape_editor->delete_segment();
782 }
784 void
785 sp_node_path_edit_break(void)
786 {
787 ShapeEditor *shape_editor = get_current_shape_editor();
788 if (shape_editor) shape_editor->break_at_nodes();
789 }
791 void
792 sp_node_path_edit_join(void)
793 {
794 ShapeEditor *shape_editor = get_current_shape_editor();
795 if (shape_editor) shape_editor->join_nodes();
796 }
798 void
799 sp_node_path_edit_join_segment(void)
800 {
801 ShapeEditor *shape_editor = get_current_shape_editor();
802 if (shape_editor) shape_editor->join_segments();
803 }
805 void
806 sp_node_path_edit_toline(void)
807 {
808 ShapeEditor *shape_editor = get_current_shape_editor();
809 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
810 }
812 void
813 sp_node_path_edit_tocurve(void)
814 {
815 ShapeEditor *shape_editor = get_current_shape_editor();
816 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
817 }
819 void
820 sp_node_path_edit_cusp(void)
821 {
822 ShapeEditor *shape_editor = get_current_shape_editor();
823 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
824 }
826 void
827 sp_node_path_edit_smooth(void)
828 {
829 ShapeEditor *shape_editor = get_current_shape_editor();
830 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
831 }
833 void
834 sp_node_path_edit_symmetrical(void)
835 {
836 ShapeEditor *shape_editor = get_current_shape_editor();
837 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
838 }
840 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
841 bool show = gtk_toggle_action_get_active( act );
842 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
843 ShapeEditor *shape_editor = get_current_shape_editor();
844 if (shape_editor) shape_editor->show_handles(show);
845 }
847 /* is called when the node selection is modified */
848 static void
849 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
850 {
851 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
852 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
853 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
854 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
856 // quit if run by the attr_changed listener
857 if (g_object_get_data( tbl, "freeze" )) {
858 return;
859 }
861 // in turn, prevent listener from responding
862 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
864 ShapeEditor *shape_editor = get_current_shape_editor();
865 if (shape_editor && shape_editor->has_nodepath()) {
866 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
867 int n_selected = 0;
868 if (nodepath) {
869 n_selected = nodepath->numSelected();
870 }
872 if (n_selected == 0) {
873 gtk_action_set_sensitive(xact, FALSE);
874 gtk_action_set_sensitive(yact, FALSE);
875 } else {
876 gtk_action_set_sensitive(xact, TRUE);
877 gtk_action_set_sensitive(yact, TRUE);
878 NR::Coord oldx = gtk_adjustment_get_value(xadj);
879 NR::Coord oldy = gtk_adjustment_get_value(xadj);
881 if (n_selected == 1) {
882 NR::Point sel_node = nodepath->singleSelectedCoords();
883 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
884 gtk_adjustment_set_value(xadj, sel_node[NR::X]);
885 gtk_adjustment_set_value(yadj, sel_node[NR::Y]);
886 }
887 } else {
888 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
889 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
890 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
891 /* Note: Currently x and y will always have a value, even if the coordinates of the
892 selected nodes don't coincide (in this case we use the coordinates of the center
893 of the bounding box). So the entries are never set to zero. */
894 gtk_adjustment_set_value(xadj, x ? (*x) : 0.0); // FIXME: Maybe we should clear the entry
895 gtk_adjustment_set_value(yadj, y ? (*y) : 0.0); // fields, not set them to zero.
896 }
897 }
898 }
899 }
901 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
902 }
904 static void
905 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
906 {
907 // quit if run by the attr_changed listener
908 if (g_object_get_data( tbl, "freeze" )) {
909 return;
910 }
912 // in turn, prevent listener from responding
913 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
915 ShapeEditor *shape_editor = get_current_shape_editor();
916 if (shape_editor && shape_editor->has_nodepath()) {
917 if (!strcmp(value_name, "x")) {
918 sp_node_selected_move_absolute(shape_editor->get_nodepath(), gtk_adjustment_get_value(adj), NR::X);
919 }
920 if (!strcmp(value_name, "y")) {
921 sp_node_selected_move_absolute(shape_editor->get_nodepath(), gtk_adjustment_get_value(adj), NR::Y);
922 }
923 }
925 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
926 }
928 static void
929 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
930 {
931 sp_node_path_value_changed(adj, tbl, "x");
932 }
934 static void
935 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
936 {
937 sp_node_path_value_changed(adj, tbl, "y");
938 }
940 //################################
941 //## Node Editing Toolbox ##
942 //################################
944 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
945 {
946 {
947 InkAction* inky = ink_action_new( "NodeInsertAction",
948 _("Insert node"),
949 _("Insert new nodes into selected segments"),
950 "node_insert",
951 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
952 g_object_set( inky, "short_label", _("Insert"), NULL );
953 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
954 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
955 }
957 {
958 InkAction* inky = ink_action_new( "NodeDeleteAction",
959 _("Delete node"),
960 _("Delete selected nodes"),
961 "node_delete",
962 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
963 g_object_set( inky, "short_label", _("Delete"), NULL );
964 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
965 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
966 }
968 {
969 InkAction* inky = ink_action_new( "NodeJoinAction",
970 _("Join endnodes"),
971 _("Join selected endnodes"),
972 "node_join",
973 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
974 g_object_set( inky, "short_label", _("Join"), NULL );
975 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
976 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
977 }
979 {
980 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
981 _("Join Segment"),
982 _("Join selected endnodes with a new segment"),
983 "node_join_segment",
984 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
985 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
986 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
987 }
989 {
990 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
991 _("Delete Segment"),
992 _("Split path between two non-endpoint nodes"),
993 "node_delete_segment",
994 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
995 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
996 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
997 }
999 {
1000 InkAction* inky = ink_action_new( "NodeBreakAction",
1001 _("Node Break"),
1002 _("Break path at selected nodes"),
1003 "node_break",
1004 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1005 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1006 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1007 }
1009 {
1010 InkAction* inky = ink_action_new( "NodeCuspAction",
1011 _("Node Cusp"),
1012 _("Make selected nodes corner"),
1013 "node_cusp",
1014 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1015 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1016 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1017 }
1019 {
1020 InkAction* inky = ink_action_new( "NodeSmoothAction",
1021 _("Node Smooth"),
1022 _("Make selected nodes smooth"),
1023 "node_smooth",
1024 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1025 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1026 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1027 }
1029 {
1030 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1031 _("Node Symmetric"),
1032 _("Make selected nodes symmetric"),
1033 "node_symmetric",
1034 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1035 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1036 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1037 }
1039 {
1040 InkAction* inky = ink_action_new( "NodeLineAction",
1041 _("Node Line"),
1042 _("Make selected segments lines"),
1043 "node_line",
1044 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1045 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1046 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1047 }
1049 {
1050 InkAction* inky = ink_action_new( "NodeCurveAction",
1051 _("Node Curve"),
1052 _("Make selected segments curves"),
1053 "node_curve",
1054 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1055 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1056 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1057 }
1059 {
1060 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1061 _("Show Handles"),
1062 _("Show the Bezier handles of selected nodes"),
1063 "nodes_show_handles",
1064 Inkscape::ICON_SIZE_DECORATION );
1065 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1066 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1067 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1068 }
1070 /* X coord of selected node(s) */
1071 {
1072 EgeAdjustmentAction* eact = 0;
1073 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1074 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1075 eact = create_adjustment_action( "NodeXAction",
1076 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1077 "tools.nodes", "Xcoord", 0,
1078 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1079 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1080 labels, values, G_N_ELEMENTS(labels),
1081 sp_node_path_x_value_changed );
1082 g_object_set_data( holder, "nodes_x_action", eact );
1083 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1084 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1085 }
1087 /* Y coord of selected node(s) */
1088 {
1089 EgeAdjustmentAction* eact = 0;
1090 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1091 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1092 eact = create_adjustment_action( "NodeYAction",
1093 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1094 "tools.nodes", "Ycoord", 0,
1095 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1096 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1097 labels, values, G_N_ELEMENTS(labels),
1098 sp_node_path_y_value_changed );
1099 g_object_set_data( holder, "nodes_y_action", eact );
1100 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1101 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1102 }
1104 sigc::connection *connection = new sigc::connection (
1105 desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(sp_node_toolbox_coord_changed), (GObject *)holder))
1106 );
1108 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1109 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1110 } // end of sp_node_toolbox_prep()
1113 //########################
1114 //## Zoom Toolbox ##
1115 //########################
1117 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1118 {
1119 // no custom GtkAction setup needed
1120 } // end of sp_zoom_toolbox_prep()
1122 void
1123 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1124 {
1125 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")));
1126 }
1129 void
1130 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1131 {
1132 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")));
1133 }
1135 void
1136 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1137 {
1138 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")));
1139 }
1141 static void
1142 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1143 {
1144 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1145 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1147 if (old_desktop) {
1148 GList *children, *iter;
1150 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1151 for ( iter = children ; iter ; iter = iter->next ) {
1152 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1153 }
1154 g_list_free(children);
1155 }
1157 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1159 if (desktop) {
1160 gtk_widget_set_sensitive(toolbox, TRUE);
1161 setup_func(toolbox, desktop);
1162 update_func(desktop, desktop->event_context, toolbox);
1163 *conn = desktop->connectEventContextChanged
1164 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1165 } else {
1166 gtk_widget_set_sensitive(toolbox, FALSE);
1167 }
1169 } // end of toolbox_set_desktop()
1172 static void
1173 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1174 {
1175 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
1176 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
1177 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
1178 // "toolbox.tools" was not set. Fallback to older value
1179 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
1181 // Copy the setting forwards
1182 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
1183 }
1184 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1186 for (int i = 0 ; tools[i].type_name ; i++ ) {
1187 GtkWidget *button =
1188 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
1189 SP_BUTTON_TYPE_TOGGLE,
1190 Inkscape::Verb::get(tools[i].verb),
1191 Inkscape::Verb::get(tools[i].doubleclick_verb),
1192 desktop,
1193 tooltips );
1195 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1196 (gpointer)button );
1197 }
1198 }
1201 static void
1202 update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
1203 {
1204 gchar const *const tname = ( eventcontext
1205 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1206 : NULL );
1207 for (int i = 0 ; tools[i].type_name ; i++ ) {
1208 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1209 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1210 }
1211 }
1213 static void
1214 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1215 {
1216 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1217 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1218 GtkUIManager* mgr = gtk_ui_manager_new();
1219 GError* errVal = 0;
1220 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1221 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1223 std::map<std::string, GtkWidget*> dataHolders;
1225 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1226 if ( aux_toolboxes[i].prep_func ) {
1227 // converted to GtkActions and UIManager
1229 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1230 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1231 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1232 dataHolders[aux_toolboxes[i].type_name] = kludge;
1233 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1234 } else {
1236 GtkWidget *sub_toolbox = 0;
1237 if (aux_toolboxes[i].create_func == NULL)
1238 sub_toolbox = sp_empty_toolbox_new(desktop);
1239 else {
1240 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1241 }
1243 gtk_size_group_add_widget( grouper, sub_toolbox );
1245 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1246 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1248 }
1249 }
1251 // Second pass to create toolbars *after* all GtkActions are created
1252 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1253 if ( aux_toolboxes[i].prep_func ) {
1254 // converted to GtkActions and UIManager
1256 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1258 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1259 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1261 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1262 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1263 g_free( tmp );
1264 tmp = 0;
1266 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1267 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1268 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1269 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1270 }
1271 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1274 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1276 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1277 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1278 swatch->setDesktop( desktop );
1279 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1280 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1281 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1282 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 );
1283 }
1285 gtk_widget_show_all( holder );
1286 sp_set_font_size_smaller( holder );
1288 gtk_size_group_add_widget( grouper, holder );
1290 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1291 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1292 }
1293 }
1295 g_object_unref( G_OBJECT(grouper) );
1296 }
1298 static void
1299 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1300 {
1301 gchar const *tname = ( eventcontext
1302 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1303 : NULL );
1304 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1305 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1306 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1307 gtk_widget_show_all(sub_toolbox);
1308 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1309 } else {
1310 gtk_widget_hide(sub_toolbox);
1311 }
1312 }
1313 }
1315 static void
1316 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1317 {
1318 gchar const * descr =
1319 "<ui>"
1320 " <toolbar name='CommandsToolbar'>"
1321 " <toolitem action='FileNew' />"
1322 " <toolitem action='FileOpen' />"
1323 " <toolitem action='FileSave' />"
1324 " <toolitem action='FilePrint' />"
1325 " <separator />"
1326 " <toolitem action='FileImport' />"
1327 " <toolitem action='FileExport' />"
1328 " <separator />"
1329 " <toolitem action='EditUndo' />"
1330 " <toolitem action='EditRedo' />"
1331 " <separator />"
1332 " <toolitem action='EditCopy' />"
1333 " <toolitem action='EditCut' />"
1334 " <toolitem action='EditPaste' />"
1335 " <separator />"
1336 " <toolitem action='ZoomSelection' />"
1337 " <toolitem action='ZoomDrawing' />"
1338 " <toolitem action='ZoomPage' />"
1339 " <separator />"
1340 " <toolitem action='EditDuplicate' />"
1341 " <toolitem action='EditClone' />"
1342 " <toolitem action='EditUnlinkClone' />"
1343 " <separator />"
1344 " <toolitem action='SelectionGroup' />"
1345 " <toolitem action='SelectionUnGroup' />"
1346 " <separator />"
1347 " <toolitem action='DialogFillStroke' />"
1348 " <toolitem action='DialogText' />"
1349 " <toolitem action='DialogXMLEditor' />"
1350 " <toolitem action='DialogAlignDistribute' />"
1351 " <separator />"
1352 " <toolitem action='DialogPreferences' />"
1353 " <toolitem action='DialogDocumentProperties' />"
1354 " </toolbar>"
1355 "</ui>";
1356 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1359 GtkUIManager* mgr = gtk_ui_manager_new();
1360 GError* errVal = 0;
1362 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1363 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1365 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1366 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1367 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1368 }
1369 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1370 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1371 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1374 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1375 }
1377 static void
1378 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1379 {
1380 }
1382 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1383 {
1384 gtk_widget_show(toolbox_toplevel);
1385 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1387 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1388 if (!shown_toolbox) {
1389 return;
1390 }
1391 gtk_widget_show(toolbox);
1393 // need to show the spacer, or the padding will be off
1394 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1395 gtk_widget_show(spacer);
1397 gtk_widget_show_all(shown_toolbox);
1398 }
1400 void
1401 aux_toolbox_space(GtkWidget *tb, gint space)
1402 {
1403 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1404 }
1406 static GtkWidget *
1407 sp_empty_toolbox_new(SPDesktop *desktop)
1408 {
1409 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1410 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1411 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1413 gtk_widget_show_all(tbl);
1414 sp_set_font_size_smaller (tbl);
1416 return tbl;
1417 }
1419 // helper UI functions
1421 GtkWidget *
1422 sp_tb_spinbutton(
1423 gchar *label, gchar const *tooltip,
1424 gchar const *path, gchar const *data, gdouble def,
1425 GtkWidget *us,
1426 GtkWidget *tbl,
1427 gboolean altx, gchar const *altx_mark,
1428 gdouble lower, gdouble upper, gdouble step, gdouble page,
1429 void (*callback)(GtkAdjustment *, GtkWidget *),
1430 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1431 {
1432 GtkTooltips *tt = gtk_tooltips_new();
1434 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1436 GtkWidget *l = gtk_label_new(label);
1437 gtk_widget_show(l);
1438 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1439 gtk_container_add(GTK_CONTAINER(hb), l);
1441 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1442 lower, upper, step, page, page);
1443 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1444 if (us)
1445 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1447 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1448 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1449 if (altx)
1450 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1451 gtk_widget_set_size_request(sb,
1452 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1453 AUX_SPINBUTTON_HEIGHT);
1454 gtk_widget_show(sb);
1455 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1456 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1457 gtk_container_add(GTK_CONTAINER(hb), sb);
1458 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1460 return hb;
1461 }
1463 #define MODE_LABEL_WIDTH 70
1465 //########################
1466 //## Star ##
1467 //########################
1469 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1470 {
1471 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1473 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1474 // do not remember prefs if this call is initiated by an undo change, because undoing object
1475 // creation sets bogus values to its attributes before it is deleted
1476 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1477 }
1479 // quit if run by the attr_changed listener
1480 if (g_object_get_data( dataKludge, "freeze" )) {
1481 return;
1482 }
1484 // in turn, prevent listener from responding
1485 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1487 bool modmade = false;
1489 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1490 GSList const *items = selection->itemList();
1491 for (; items != NULL; items = items->next) {
1492 if (SP_IS_STAR((SPItem *) items->data)) {
1493 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1494 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1495 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1496 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1497 + M_PI / (gint)adj->value));
1498 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1499 modmade = true;
1500 }
1501 }
1502 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1503 _("Star: Change number of corners"));
1505 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1506 }
1508 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1509 {
1510 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1512 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1513 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1514 }
1516 // quit if run by the attr_changed listener
1517 if (g_object_get_data( dataKludge, "freeze" )) {
1518 return;
1519 }
1521 // in turn, prevent listener from responding
1522 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1524 bool modmade = false;
1525 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1526 GSList const *items = selection->itemList();
1527 for (; items != NULL; items = items->next) {
1528 if (SP_IS_STAR((SPItem *) items->data)) {
1529 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1531 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1532 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1533 if (r2 < r1) {
1534 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1535 } else {
1536 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1537 }
1539 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1540 modmade = true;
1541 }
1542 }
1544 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1545 _("Star: Change spoke ratio"));
1547 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1548 }
1550 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1551 {
1552 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1553 bool flat = ege_select_one_action_get_active( act ) == 0;
1555 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1556 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1557 flat ? "true" : "false" );
1558 }
1560 // quit if run by the attr_changed listener
1561 if (g_object_get_data( dataKludge, "freeze" )) {
1562 return;
1563 }
1565 // in turn, prevent listener from responding
1566 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1568 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1569 GSList const *items = selection->itemList();
1570 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1571 bool modmade = false;
1573 if ( prop_action ) {
1574 gtk_action_set_sensitive( prop_action, !flat );
1575 }
1577 for (; items != NULL; items = items->next) {
1578 if (SP_IS_STAR((SPItem *) items->data)) {
1579 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1580 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1581 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1582 modmade = true;
1583 }
1584 }
1586 if (modmade) {
1587 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1588 flat ? _("Make polygon") : _("Make star"));
1589 }
1591 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1592 }
1594 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1595 {
1596 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1598 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1599 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1600 }
1602 // quit if run by the attr_changed listener
1603 if (g_object_get_data( dataKludge, "freeze" )) {
1604 return;
1605 }
1607 // in turn, prevent listener from responding
1608 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1610 bool modmade = false;
1612 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1613 GSList const *items = selection->itemList();
1614 for (; items != NULL; items = items->next) {
1615 if (SP_IS_STAR((SPItem *) items->data)) {
1616 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1617 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1618 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1619 modmade = true;
1620 }
1621 }
1622 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1623 _("Star: Change rounding"));
1625 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1626 }
1628 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1629 {
1630 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1632 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1633 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1634 }
1636 // quit if run by the attr_changed listener
1637 if (g_object_get_data( dataKludge, "freeze" )) {
1638 return;
1639 }
1641 // in turn, prevent listener from responding
1642 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1644 bool modmade = false;
1646 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1647 GSList const *items = selection->itemList();
1648 for (; items != NULL; items = items->next) {
1649 if (SP_IS_STAR((SPItem *) items->data)) {
1650 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1651 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1652 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1653 modmade = true;
1654 }
1655 }
1656 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1657 _("Star: Change randomization"));
1659 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1660 }
1663 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1664 gchar const */*old_value*/, gchar const */*new_value*/,
1665 bool /*is_interactive*/, gpointer data)
1666 {
1667 GtkWidget *tbl = GTK_WIDGET(data);
1669 // quit if run by the _changed callbacks
1670 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1671 return;
1672 }
1674 // in turn, prevent callbacks from responding
1675 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1677 GtkAdjustment *adj = 0;
1679 if (!strcmp(name, "inkscape:randomized")) {
1680 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1681 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1682 } else if (!strcmp(name, "inkscape:rounded")) {
1683 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1684 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1685 } else if (!strcmp(name, "inkscape:flatsided")) {
1686 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1687 char const *flatsides = repr->attribute("inkscape:flatsided");
1688 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1689 if ( flatsides && !strcmp(flatsides,"false") ) {
1690 ege_select_one_action_set_active( flat_action, 1 );
1691 gtk_action_set_sensitive( prop_action, TRUE );
1692 } else {
1693 ege_select_one_action_set_active( flat_action, 0 );
1694 gtk_action_set_sensitive( prop_action, FALSE );
1695 }
1696 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1697 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1698 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1699 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1700 if (r2 < r1) {
1701 gtk_adjustment_set_value(adj, r2/r1);
1702 } else {
1703 gtk_adjustment_set_value(adj, r1/r2);
1704 }
1705 } else if (!strcmp(name, "sodipodi:sides")) {
1706 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1707 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1708 }
1710 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1711 }
1714 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1715 {
1716 NULL, /* child_added */
1717 NULL, /* child_removed */
1718 star_tb_event_attr_changed,
1719 NULL, /* content_changed */
1720 NULL /* order_changed */
1721 };
1724 /**
1725 * \param selection Should not be NULL.
1726 */
1727 static void
1728 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1729 {
1730 int n_selected = 0;
1731 Inkscape::XML::Node *repr = NULL;
1733 purge_repr_listener( tbl, tbl );
1735 for (GSList const *items = selection->itemList();
1736 items != NULL;
1737 items = items->next)
1738 {
1739 if (SP_IS_STAR((SPItem *) items->data)) {
1740 n_selected++;
1741 repr = SP_OBJECT_REPR((SPItem *) items->data);
1742 }
1743 }
1745 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1747 if (n_selected == 0) {
1748 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1749 } else if (n_selected == 1) {
1750 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1752 if (repr) {
1753 g_object_set_data( tbl, "repr", repr );
1754 Inkscape::GC::anchor(repr);
1755 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1756 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1757 }
1758 } else {
1759 // FIXME: implement averaging of all parameters for multiple selected stars
1760 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1761 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1762 }
1763 }
1766 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
1767 {
1768 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1769 // callbacks to lump all the changes for all selected objects in one undo step
1771 GtkAdjustment *adj = 0;
1773 // fixme: make settable in prefs!
1774 gint mag = 5;
1775 gdouble prop = 0.5;
1776 gboolean flat = FALSE;
1777 gdouble randomized = 0;
1778 gdouble rounded = 0;
1780 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1781 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1783 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1784 gtk_action_set_sensitive( sb2, !flat );
1786 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1787 gtk_adjustment_set_value(adj, mag);
1788 gtk_adjustment_value_changed(adj);
1790 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1791 gtk_adjustment_set_value(adj, prop);
1792 gtk_adjustment_value_changed(adj);
1794 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1795 gtk_adjustment_set_value(adj, rounded);
1796 gtk_adjustment_value_changed(adj);
1798 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1799 gtk_adjustment_set_value(adj, randomized);
1800 gtk_adjustment_value_changed(adj);
1801 }
1804 void
1805 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1806 {
1807 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1808 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1809 GtkWidget *l = gtk_label_new(NULL);
1810 gtk_label_set_markup(GTK_LABEL(l), title);
1811 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1812 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1813 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1814 }
1817 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1818 {
1819 {
1820 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1821 ege_output_action_set_use_markup( act, TRUE );
1822 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1823 g_object_set_data( holder, "mode_action", act );
1824 }
1826 {
1827 //EgeAdjustmentAction* calligraphy_angle = 0;
1828 EgeAdjustmentAction* eact = 0;
1829 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1830 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1832 /* Flatsided checkbox */
1833 {
1834 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1836 GtkTreeIter iter;
1837 gtk_list_store_append( model, &iter );
1838 gtk_list_store_set( model, &iter,
1839 0, _("Polygon"),
1840 1, _("Regular polygon (with one handle) instead of a star"),
1841 2, "star_flat",
1842 -1 );
1844 gtk_list_store_append( model, &iter );
1845 gtk_list_store_set( model, &iter,
1846 0, _("Star"),
1847 1, _("Star instead of a regular polygon (with one handle)"),
1848 2, "star_angled",
1849 -1 );
1851 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
1852 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1853 g_object_set_data( holder, "flat_action", act );
1855 ege_select_one_action_set_appearance( act, "full" );
1856 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1857 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1858 ege_select_one_action_set_icon_column( act, 2 );
1859 ege_select_one_action_set_tooltip_column( act, 1 );
1861 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1862 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1863 }
1865 /* Magnitude */
1866 {
1867 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
1868 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
1869 eact = create_adjustment_action( "MagnitudeAction",
1870 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
1871 "tools.shapes.star", "magnitude", 3,
1872 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1873 3, 1024, 1, 5,
1874 labels, values, G_N_ELEMENTS(labels),
1875 sp_stb_magnitude_value_changed,
1876 1.0, 0 );
1877 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1878 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1879 }
1881 /* Spoke ratio */
1882 {
1883 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
1884 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
1885 eact = create_adjustment_action( "SpokeAction",
1886 _("Spoke ratio"), _("Spoke ratio:"),
1887 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1888 // Base radius is the same for the closest handle.
1889 _("Base radius to tip radius ratio"),
1890 "tools.shapes.star", "proportion", 0.5,
1891 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1892 0.01, 1.0, 0.01, 0.1,
1893 labels, values, G_N_ELEMENTS(labels),
1894 sp_stb_proportion_value_changed );
1895 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1896 g_object_set_data( holder, "prop_action", eact );
1897 }
1899 if ( !isFlatSided ) {
1900 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1901 } else {
1902 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1903 }
1905 /* Roundedness */
1906 {
1907 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
1908 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
1909 eact = create_adjustment_action( "RoundednessAction",
1910 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1911 "tools.shapes.star", "rounded", 0.0,
1912 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1913 -10.0, 10.0, 0.01, 0.1,
1914 labels, values, G_N_ELEMENTS(labels),
1915 sp_stb_rounded_value_changed );
1916 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1917 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1918 }
1920 /* Randomization */
1921 {
1922 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
1923 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
1924 eact = create_adjustment_action( "RandomizationAction",
1925 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
1926 "tools.shapes.star", "randomized", 0.0,
1927 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1928 -10.0, 10.0, 0.001, 0.01,
1929 labels, values, G_N_ELEMENTS(labels),
1930 sp_stb_randomized_value_changed, 0.1, 3 );
1931 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1932 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1933 }
1934 }
1936 {
1937 /* Reset */
1938 {
1939 GtkAction* act = gtk_action_new( "StarResetAction",
1940 _("Defaults"),
1941 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1942 GTK_STOCK_CLEAR );
1943 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1944 gtk_action_group_add_action( mainActions, act );
1945 gtk_action_set_sensitive( act, TRUE );
1946 }
1947 }
1949 sigc::connection *connection = new sigc::connection(
1950 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1951 );
1952 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1953 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1954 }
1957 //########################
1958 //## Rect ##
1959 //########################
1961 static void sp_rtb_sensitivize( GObject *tbl )
1962 {
1963 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
1964 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
1965 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
1967 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
1968 gtk_action_set_sensitive( not_rounded, FALSE );
1969 } else {
1970 gtk_action_set_sensitive( not_rounded, TRUE );
1971 }
1972 }
1975 static void
1976 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
1977 void (*setter)(SPRect *, gdouble))
1978 {
1979 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1981 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1982 SPUnit const *unit = tracker->getActiveUnit();
1984 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1985 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1986 }
1988 // quit if run by the attr_changed listener
1989 if (g_object_get_data( tbl, "freeze" )) {
1990 return;
1991 }
1993 // in turn, prevent listener from responding
1994 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1996 bool modmade = false;
1997 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1998 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1999 if (SP_IS_RECT(items->data)) {
2000 if (adj->value != 0) {
2001 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2002 } else {
2003 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2004 }
2005 modmade = true;
2006 }
2007 }
2009 sp_rtb_sensitivize( tbl );
2011 if (modmade) {
2012 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2013 _("Change rectangle"));
2014 }
2016 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2017 }
2019 static void
2020 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2021 {
2022 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2023 }
2025 static void
2026 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2027 {
2028 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2029 }
2031 static void
2032 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2033 {
2034 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2035 }
2037 static void
2038 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2039 {
2040 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2041 }
2045 static void
2046 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2047 {
2048 GtkAdjustment *adj = 0;
2050 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2051 gtk_adjustment_set_value(adj, 0.0);
2052 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2053 gtk_adjustment_value_changed(adj);
2055 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2056 gtk_adjustment_set_value(adj, 0.0);
2057 gtk_adjustment_value_changed(adj);
2059 sp_rtb_sensitivize( obj );
2060 }
2062 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2063 gchar const */*old_value*/, gchar const */*new_value*/,
2064 bool /*is_interactive*/, gpointer data)
2065 {
2066 GObject *tbl = G_OBJECT(data);
2068 // quit if run by the _changed callbacks
2069 if (g_object_get_data( tbl, "freeze" )) {
2070 return;
2071 }
2073 // in turn, prevent callbacks from responding
2074 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2076 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2077 SPUnit const *unit = tracker->getActiveUnit();
2079 gpointer item = g_object_get_data( tbl, "item" );
2080 if (item && SP_IS_RECT(item)) {
2081 {
2082 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2083 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2084 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2085 }
2087 {
2088 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2089 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2090 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2091 }
2093 {
2094 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2095 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2096 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2097 }
2099 {
2100 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2101 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2102 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2103 }
2104 }
2106 sp_rtb_sensitivize( tbl );
2108 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2109 }
2112 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2113 NULL, /* child_added */
2114 NULL, /* child_removed */
2115 rect_tb_event_attr_changed,
2116 NULL, /* content_changed */
2117 NULL /* order_changed */
2118 };
2120 /**
2121 * \param selection should not be NULL.
2122 */
2123 static void
2124 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2125 {
2126 int n_selected = 0;
2127 Inkscape::XML::Node *repr = NULL;
2128 SPItem *item = NULL;
2130 if ( g_object_get_data( tbl, "repr" ) ) {
2131 g_object_set_data( tbl, "item", NULL );
2132 }
2133 purge_repr_listener( tbl, tbl );
2135 for (GSList const *items = selection->itemList();
2136 items != NULL;
2137 items = items->next) {
2138 if (SP_IS_RECT((SPItem *) items->data)) {
2139 n_selected++;
2140 item = (SPItem *) items->data;
2141 repr = SP_OBJECT_REPR(item);
2142 }
2143 }
2145 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2147 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2149 if (n_selected == 0) {
2150 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2152 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2153 gtk_action_set_sensitive(w, FALSE);
2154 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2155 gtk_action_set_sensitive(h, FALSE);
2157 } else if (n_selected == 1) {
2158 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2159 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2161 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2162 gtk_action_set_sensitive(w, TRUE);
2163 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2164 gtk_action_set_sensitive(h, TRUE);
2166 if (repr) {
2167 g_object_set_data( tbl, "repr", repr );
2168 g_object_set_data( tbl, "item", item );
2169 Inkscape::GC::anchor(repr);
2170 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2171 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2172 }
2173 } else {
2174 // FIXME: implement averaging of all parameters for multiple selected
2175 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2176 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2177 sp_rtb_sensitivize( tbl );
2178 }
2179 }
2182 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2183 {
2184 EgeAdjustmentAction* eact = 0;
2186 {
2187 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2188 ege_output_action_set_use_markup( act, TRUE );
2189 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2190 g_object_set_data( holder, "mode_action", act );
2191 }
2193 // rx/ry units menu: create
2194 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2195 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2196 // fixme: add % meaning per cent of the width/height
2197 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2198 g_object_set_data( holder, "tracker", tracker );
2200 /* W */
2201 {
2202 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2203 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2204 eact = create_adjustment_action( "RectWidthAction",
2205 _("Width"), _("W:"), _("Width of rectangle"),
2206 "tools.shapes.rect", "width", 0,
2207 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2208 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2209 labels, values, G_N_ELEMENTS(labels),
2210 sp_rtb_width_value_changed );
2211 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2212 g_object_set_data( holder, "width_action", eact );
2213 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2214 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2215 }
2217 /* H */
2218 {
2219 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2220 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2221 eact = create_adjustment_action( "RectHeightAction",
2222 _("Height"), _("H:"), _("Height of rectangle"),
2223 "tools.shapes.rect", "height", 0,
2224 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2225 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2226 labels, values, G_N_ELEMENTS(labels),
2227 sp_rtb_height_value_changed );
2228 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2229 g_object_set_data( holder, "height_action", eact );
2230 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2231 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2232 }
2234 /* rx */
2235 {
2236 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2237 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2238 eact = create_adjustment_action( "RadiusXAction",
2239 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2240 "tools.shapes.rect", "rx", 0,
2241 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2242 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2243 labels, values, G_N_ELEMENTS(labels),
2244 sp_rtb_rx_value_changed);
2245 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2246 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2247 }
2249 /* ry */
2250 {
2251 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2252 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2253 eact = create_adjustment_action( "RadiusYAction",
2254 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2255 "tools.shapes.rect", "ry", 0,
2256 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2257 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2258 labels, values, G_N_ELEMENTS(labels),
2259 sp_rtb_ry_value_changed);
2260 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2261 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2262 }
2264 // add the units menu
2265 {
2266 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2267 gtk_action_group_add_action( mainActions, act );
2268 }
2270 /* Reset */
2271 {
2272 InkAction* inky = ink_action_new( "RectResetAction",
2273 _("Not rounded"),
2274 _("Make corners sharp"),
2275 "squared_corner",
2276 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2277 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2278 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2279 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2280 g_object_set_data( holder, "not_rounded", inky );
2281 }
2283 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2284 sp_rtb_sensitivize( holder );
2286 sigc::connection *connection = new sigc::connection(
2287 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2288 );
2289 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2290 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2291 }
2293 //########################
2294 //## 3D Box ##
2295 //########################
2297 static void sp_3dbox_toggle_vp_changed (GtkToggleAction */*act*/, GObject *dataKludge, Box3D::Axis axis)
2298 {
2299 SPDesktop *desktop = (SPDesktop *) g_object_get_data (dataKludge, "desktop");
2300 SPDocument *document = sp_desktop_document (desktop);
2301 Box3D::Perspective3D *persp = document->current_perspective;
2303 g_return_if_fail (is_single_axis_direction (axis));
2304 g_return_if_fail (persp);
2306 persp->toggle_boxes (axis);
2308 gchar *str;
2309 switch (axis) {
2310 case Box3D::X:
2311 str = g_strdup ("box3d_angle_x_action");
2312 break;
2313 case Box3D::Y:
2314 str = g_strdup ("box3d_angle_y_action");
2315 break;
2316 case Box3D::Z:
2317 str = g_strdup ("box3d_angle_z_action");
2318 break;
2319 default:
2320 return;
2321 }
2322 GtkAction* angle_action = GTK_ACTION (g_object_get_data (dataKludge, str));
2323 if (angle_action) {
2324 gtk_action_set_sensitive (angle_action, !persp->get_vanishing_point (axis)->is_finite() );
2325 }
2327 // FIXME: Given how it is realized in the other tools, this is probably not the right way to do it,
2328 // but without the if construct, we get continuous segfaults. Needs further investigation.
2329 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2330 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
2331 _("3D Box: Change perspective"));
2332 }
2333 }
2335 static void sp_3dbox_toggle_vp_x_changed(GtkToggleAction *act, GObject *dataKludge)
2336 {
2337 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::X);
2338 }
2340 static void sp_3dbox_toggle_vp_y_changed(GtkToggleAction *act, GObject *dataKludge)
2341 {
2342 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Y);
2343 }
2345 static void sp_3dbox_toggle_vp_z_changed(GtkToggleAction *act, GObject *dataKludge)
2346 {
2347 sp_3dbox_toggle_vp_changed (act, dataKludge, Box3D::Z);
2348 }
2350 static void sp_3dbox_vp_angle_changed(GtkAdjustment *adj, GObject *dataKludge, Box3D::Axis axis )
2351 {
2352 SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
2353 Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
2355 if (persp) {
2356 double angle = adj->value * M_PI/180;
2357 persp->set_infinite_direction (axis, NR::Point (cos (angle), sin (angle)));
2359 // FIXME: See comment above; without the if construct we get segfaults during undo.
2360 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2361 sp_document_maybe_done(sp_desktop_document(desktop), "perspectiveangle", SP_VERB_CONTEXT_3DBOX,
2362 _("3D Box: Change perspective"));
2363 }
2364 }
2365 //g_object_set_data(G_OBJECT(dataKludge), "freeze", GINT_TO_POINTER(FALSE));
2366 }
2368 static void sp_3dbox_vpx_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2369 {
2370 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::X);
2371 }
2373 static void sp_3dbox_vpy_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2374 {
2375 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Y);
2376 }
2378 static void sp_3dbox_vpz_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2379 {
2380 sp_3dbox_vp_angle_changed (adj, dataKludge, Box3D::Z);
2381 }
2383 // normalize angle so that it lies in the interval [0,360]
2384 static double sp_3dbox_normalize_angle (double a) {
2385 double angle = a + ((int) (a/360.0))*360;
2386 if (angle < 0) {
2387 angle += 360.0;
2388 }
2389 return angle;
2390 }
2392 static void sp_3dbox_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const *name,
2393 gchar const */*old_value*/, gchar const */*new_value*/,
2394 bool /*is_interactive*/, gpointer data)
2395 {
2396 GtkWidget *tbl = GTK_WIDGET(data);
2398 // FIXME: if we check for "freeze" as in other tools, no action is performed at all ...
2399 /***
2400 // quit if run by the _changed callbacks
2401 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2402 return;
2403 }
2405 // in turn, prevent callbacks from responding
2406 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2407 ***/
2409 if (!strcmp(name, "inkscape:perspective")) {
2410 GtkAdjustment *adj = 0;
2411 double angle;
2412 SPDesktop *desktop = (SPDesktop *) g_object_get_data(G_OBJECT(tbl), "desktop");
2413 Box3D::Perspective3D *persp = sp_desktop_document (desktop)->current_perspective;
2415 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_x"));
2416 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::X)->get_angle());
2417 gtk_adjustment_set_value(adj, angle);
2419 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_y"));
2420 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Y)->get_angle());
2421 gtk_adjustment_set_value(adj, angle);
2423 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_z"));
2424 angle = sp_3dbox_normalize_angle (persp->get_vanishing_point (Box3D::Z)->get_angle());
2425 gtk_adjustment_set_value(adj, angle);
2426 }
2427 }
2429 static Inkscape::XML::NodeEventVector sp_3dbox_tb_repr_events =
2430 {
2431 NULL, /* child_added */
2432 NULL, /* child_removed */
2433 sp_3dbox_tb_event_attr_changed,
2434 NULL, /* content_changed */
2435 NULL /* order_changed */
2436 };
2438 /**
2439 * \param selection Should not be NULL.
2440 */
2441 static void
2442 sp_3dbox_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2443 {
2444 Inkscape::XML::Node *repr = NULL;
2445 purge_repr_listener(tbl, tbl);
2447 SPItem *item = selection->singleItem();
2448 if (item) {
2449 repr = SP_OBJECT_REPR(item);
2450 if (repr) {
2451 g_object_set_data(tbl, "repr", repr);
2452 Inkscape::GC::anchor(repr);
2453 sp_repr_add_listener(repr, &sp_3dbox_tb_repr_events, tbl);
2454 sp_repr_synthesize_events(repr, &sp_3dbox_tb_repr_events, tbl);
2455 }
2456 }
2457 }
2459 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2460 {
2461 EgeAdjustmentAction* eact = 0;
2462 SPDocument *document = sp_desktop_document (desktop);
2463 Box3D::Perspective3D *persp = document->current_perspective;
2464 bool toggled = false;
2466 /* angle of VP in X direction */
2467 eact = create_adjustment_action("3DBoxPosAngleXAction",
2468 _("Angle X"), _("Angle X:"), _("Angle of infinite vanishing point in X direction"),
2469 "tools.shapes.3dbox", "dir_vp_x", persp->get_vanishing_point (Box3D::X)->get_angle(),
2470 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2471 0.0, 360.0, 1.0, 10.0,
2472 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2473 sp_3dbox_vpx_angle_changed,
2474 0.1, 1);
2475 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2476 g_object_set_data(holder, "box3d_angle_x_action", eact);
2477 if (!persp->get_vanishing_point (Box3D::X)->is_finite()) {
2478 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2479 } else {
2480 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2481 }
2483 /* toggle VP in X direction */
2484 {
2485 InkToggleAction* act = ink_toggle_action_new("3DBoxVPXAction",
2486 _("Toggle VP in X direction"),
2487 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2488 "toggle_vp_x",
2489 Inkscape::ICON_SIZE_DECORATION);
2490 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2491 if (persp) {
2492 toggled = !persp->get_vanishing_point(Box3D::X)->is_finite();
2493 }
2494 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2495 /* we connect the signal after setting the state to avoid switching the state again */
2496 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_x_changed), holder);
2497 }
2499 /* angle of VP in Y direction */
2500 eact = create_adjustment_action("3DBoxPosAngleYAction",
2501 _("Angle Y"), _("Angle Y:"), _("Angle of infinite vanishing point in Y direction"),
2502 "tools.shapes.3dbox", "dir_vp_y", persp->get_vanishing_point (Box3D::Y)->get_angle(),
2503 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2504 0.0, 360.0, 1.0, 10.0,
2505 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2506 sp_3dbox_vpy_angle_changed,
2507 0.1, 1);
2508 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2509 g_object_set_data(holder, "box3d_angle_y_action", eact);
2510 if (!persp->get_vanishing_point (Box3D::Y)->is_finite()) {
2511 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2512 } else {
2513 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2514 }
2516 /* toggle VP in Y direction */
2517 {
2518 InkToggleAction* act = ink_toggle_action_new("3DBoxVPYAction",
2519 _("Toggle VP in Y direction"),
2520 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2521 "toggle_vp_y",
2522 Inkscape::ICON_SIZE_DECORATION);
2523 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2524 if (persp) {
2525 toggled = !persp->get_vanishing_point(Box3D::Y)->is_finite();
2526 }
2527 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2528 /* we connect the signal after setting the state to avoid switching the state again */
2529 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_y_changed), holder);
2530 }
2532 /* angle of VP in Z direction */
2533 eact = create_adjustment_action("3DBoxPosAngleZAction",
2534 _("Angle Z"), _("Angle Z:"), _("Angle of infinite vanishing point in Z direction"),
2535 "tools.shapes.3dbox", "dir_vp_z", persp->get_vanishing_point (Box3D::Z)->get_angle(),
2536 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2537 0.0, 360.0, 1.0, 10.0,
2538 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2539 sp_3dbox_vpz_angle_changed,
2540 0.1, 1);
2542 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2543 g_object_set_data(holder, "box3d_angle_z_action", eact);
2544 if (!persp->get_vanishing_point (Box3D::Z)->is_finite()) {
2545 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2546 } else {
2547 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2548 }
2550 /* toggle VP in Z direction */
2551 {
2552 InkToggleAction* act = ink_toggle_action_new("3DBoxVPZAction",
2553 _("Toggle VP in Z direction"),
2554 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
2555 "toggle_vp_z",
2556 Inkscape::ICON_SIZE_DECORATION);
2557 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2558 if (persp) {
2559 toggled = !persp->get_vanishing_point(Box3D::Z)->is_finite();
2560 }
2561 /* we connect the signal after setting the state to avoid switching the state again */
2562 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), toggled);
2563 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_z_changed), holder);
2564 }
2566 sigc::connection *connection = new sigc::connection(
2567 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_3dbox_toolbox_selection_changed), (GObject *)holder))
2568 );
2569 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
2570 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
2571 }
2573 //########################
2574 //## Spiral ##
2575 //########################
2577 static void
2578 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2579 {
2580 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2582 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2583 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2584 }
2586 // quit if run by the attr_changed listener
2587 if (g_object_get_data( tbl, "freeze" )) {
2588 return;
2589 }
2591 // in turn, prevent listener from responding
2592 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2594 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2596 bool modmade = false;
2597 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2598 items != NULL;
2599 items = items->next)
2600 {
2601 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2602 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2603 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2604 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2605 modmade = true;
2606 }
2607 }
2609 g_free(namespaced_name);
2611 if (modmade) {
2612 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2613 _("Change spiral"));
2614 }
2616 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2617 }
2619 static void
2620 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2621 {
2622 sp_spl_tb_value_changed(adj, tbl, "revolution");
2623 }
2625 static void
2626 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2627 {
2628 sp_spl_tb_value_changed(adj, tbl, "expansion");
2629 }
2631 static void
2632 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2633 {
2634 sp_spl_tb_value_changed(adj, tbl, "t0");
2635 }
2637 static void
2638 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
2639 {
2640 GtkWidget *tbl = GTK_WIDGET(obj);
2642 GtkAdjustment *adj;
2644 // fixme: make settable
2645 gdouble rev = 5;
2646 gdouble exp = 1.0;
2647 gdouble t0 = 0.0;
2649 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2650 gtk_adjustment_set_value(adj, rev);
2651 gtk_adjustment_value_changed(adj);
2653 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2654 gtk_adjustment_set_value(adj, exp);
2655 gtk_adjustment_value_changed(adj);
2657 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2658 gtk_adjustment_set_value(adj, t0);
2659 gtk_adjustment_value_changed(adj);
2661 spinbutton_defocus(GTK_OBJECT(tbl));
2662 }
2665 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2666 gchar const */*old_value*/, gchar const */*new_value*/,
2667 bool /*is_interactive*/, gpointer data)
2668 {
2669 GtkWidget *tbl = GTK_WIDGET(data);
2671 // quit if run by the _changed callbacks
2672 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2673 return;
2674 }
2676 // in turn, prevent callbacks from responding
2677 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2679 GtkAdjustment *adj;
2680 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2681 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2683 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2684 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2686 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2687 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2689 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2690 }
2693 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2694 NULL, /* child_added */
2695 NULL, /* child_removed */
2696 spiral_tb_event_attr_changed,
2697 NULL, /* content_changed */
2698 NULL /* order_changed */
2699 };
2701 static void
2702 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2703 {
2704 int n_selected = 0;
2705 Inkscape::XML::Node *repr = NULL;
2707 purge_repr_listener( tbl, tbl );
2709 for (GSList const *items = selection->itemList();
2710 items != NULL;
2711 items = items->next)
2712 {
2713 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2714 n_selected++;
2715 repr = SP_OBJECT_REPR((SPItem *) items->data);
2716 }
2717 }
2719 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2721 if (n_selected == 0) {
2722 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2723 } else if (n_selected == 1) {
2724 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2726 if (repr) {
2727 g_object_set_data( tbl, "repr", repr );
2728 Inkscape::GC::anchor(repr);
2729 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2730 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2731 }
2732 } else {
2733 // FIXME: implement averaging of all parameters for multiple selected
2734 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2735 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2736 }
2737 }
2740 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2741 {
2742 EgeAdjustmentAction* eact = 0;
2744 {
2745 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2746 ege_output_action_set_use_markup( act, TRUE );
2747 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2748 g_object_set_data( holder, "mode_action", act );
2749 }
2751 /* Revolution */
2752 {
2753 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
2754 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2755 eact = create_adjustment_action( "SpiralRevolutionAction",
2756 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
2757 "tools.shapes.spiral", "revolution", 3.0,
2758 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2759 0.01, 1024.0, 0.1, 1.0,
2760 labels, values, G_N_ELEMENTS(labels),
2761 sp_spl_tb_revolution_value_changed, 1, 2);
2762 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2763 }
2765 /* Expansion */
2766 {
2767 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
2768 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
2769 eact = create_adjustment_action( "SpiralExpansionAction",
2770 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2771 "tools.shapes.spiral", "expansion", 1.0,
2772 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2773 0.0, 1000.0, 0.01, 1.0,
2774 labels, values, G_N_ELEMENTS(labels),
2775 sp_spl_tb_expansion_value_changed);
2776 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2777 }
2779 /* T0 */
2780 {
2781 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
2782 gdouble values[] = {0, 0.5, 0.9};
2783 eact = create_adjustment_action( "SpiralT0Action",
2784 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2785 "tools.shapes.spiral", "t0", 0.0,
2786 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2787 0.0, 0.999, 0.01, 1.0,
2788 labels, values, G_N_ELEMENTS(labels),
2789 sp_spl_tb_t0_value_changed);
2790 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2791 }
2793 /* Reset */
2794 {
2795 InkAction* inky = ink_action_new( "SpiralResetAction",
2796 _("Defaults"),
2797 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2798 GTK_STOCK_CLEAR,
2799 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2800 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2801 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2802 }
2805 sigc::connection *connection = new sigc::connection(
2806 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2807 );
2808 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2809 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2810 }
2812 //########################
2813 //## Pen/Pencil ##
2814 //########################
2817 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2818 {
2819 // Put stuff here
2820 }
2822 static void sp_pencil_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2823 {
2824 // Put stuff here
2825 }
2827 //########################
2828 //## Tweak ##
2829 //########################
2831 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2832 {
2833 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
2834 }
2836 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2837 {
2838 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
2839 }
2841 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
2842 {
2843 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2844 }
2846 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
2847 {
2848 int mode = ege_select_one_action_get_active( act );
2849 prefs_set_int_attribute("tools.tweak", "mode", mode);
2851 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
2852 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
2853 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
2854 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
2855 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
2856 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
2857 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
2858 if (doh) gtk_action_set_sensitive (doh, TRUE);
2859 if (dos) gtk_action_set_sensitive (dos, TRUE);
2860 if (dol) gtk_action_set_sensitive (dol, TRUE);
2861 if (doo) gtk_action_set_sensitive (doo, TRUE);
2862 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
2863 if (fid) gtk_action_set_sensitive (fid, FALSE);
2864 } else {
2865 if (doh) gtk_action_set_sensitive (doh, FALSE);
2866 if (dos) gtk_action_set_sensitive (dos, FALSE);
2867 if (dol) gtk_action_set_sensitive (dol, FALSE);
2868 if (doo) gtk_action_set_sensitive (doo, FALSE);
2869 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
2870 if (fid) gtk_action_set_sensitive (fid, TRUE);
2871 }
2872 }
2874 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2875 {
2876 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
2877 }
2879 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
2880 bool show = gtk_toggle_action_get_active( act );
2881 prefs_set_int_attribute ("tools.tweak", "doh", show ? 1 : 0);
2882 }
2883 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
2884 bool show = gtk_toggle_action_get_active( act );
2885 prefs_set_int_attribute ("tools.tweak", "dos", show ? 1 : 0);
2886 }
2887 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
2888 bool show = gtk_toggle_action_get_active( act );
2889 prefs_set_int_attribute ("tools.tweak", "dol", show ? 1 : 0);
2890 }
2891 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
2892 bool show = gtk_toggle_action_get_active( act );
2893 prefs_set_int_attribute ("tools.tweak", "doo", show ? 1 : 0);
2894 }
2896 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2897 {
2898 {
2899 /* Width */
2900 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
2901 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2902 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
2903 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
2904 "tools.tweak", "width", 15,
2905 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
2906 1, 100, 1.0, 10.0,
2907 labels, values, G_N_ELEMENTS(labels),
2908 sp_tweak_width_value_changed, 0.01, 0, 100 );
2909 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2910 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2911 }
2914 {
2915 /* Force */
2916 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
2917 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
2918 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
2919 _("Force"), _("Force:"), _("The force of the tweak action"),
2920 "tools.tweak", "force", 20,
2921 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
2922 1, 100, 1.0, 10.0,
2923 labels, values, G_N_ELEMENTS(labels),
2924 sp_tweak_force_value_changed, 0.01, 0, 100 );
2925 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2926 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2927 }
2929 /* Mode */
2930 {
2931 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2933 GtkTreeIter iter;
2934 gtk_list_store_append( model, &iter );
2935 gtk_list_store_set( model, &iter,
2936 0, _("Push mode"),
2937 1, _("Push parts of paths in any direction"),
2938 2, "tweak_push_mode",
2939 -1 );
2941 gtk_list_store_append( model, &iter );
2942 gtk_list_store_set( model, &iter,
2943 0, _("Shrink mode"),
2944 1, _("Shrink (inset) parts of paths"),
2945 2, "tweak_shrink_mode",
2946 -1 );
2948 gtk_list_store_append( model, &iter );
2949 gtk_list_store_set( model, &iter,
2950 0, _("Grow mode"),
2951 1, _("Grow (outset) parts of paths"),
2952 2, "tweak_grow_mode",
2953 -1 );
2955 gtk_list_store_append( model, &iter );
2956 gtk_list_store_set( model, &iter,
2957 0, _("Attract mode"),
2958 1, _("Attract parts of paths towards cursor"),
2959 2, "tweak_attract_mode",
2960 -1 );
2962 gtk_list_store_append( model, &iter );
2963 gtk_list_store_set( model, &iter,
2964 0, _("Repel mode"),
2965 1, _("Repel parts of paths from cursor"),
2966 2, "tweak_repel_mode",
2967 -1 );
2969 gtk_list_store_append( model, &iter );
2970 gtk_list_store_set( model, &iter,
2971 0, _("Roughen mode"),
2972 1, _("Roughen parts of paths"),
2973 2, "tweak_roughen_mode",
2974 -1 );
2976 gtk_list_store_append( model, &iter );
2977 gtk_list_store_set( model, &iter,
2978 0, _("Color paint mode"),
2979 1, _("Paint the tool's color upon selected objects"),
2980 2, "tweak_colorpaint_mode",
2981 -1 );
2983 gtk_list_store_append( model, &iter );
2984 gtk_list_store_set( model, &iter,
2985 0, _("Color jitter mode"),
2986 1, _("Jitter the colors of selected objects"),
2987 2, "tweak_colorjitter_mode",
2988 -1 );
2990 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
2991 g_object_set( act, "short_label", _("Mode:"), NULL );
2992 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2993 g_object_set_data( holder, "mode_action", act );
2995 ege_select_one_action_set_appearance( act, "full" );
2996 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2997 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2998 ege_select_one_action_set_icon_column( act, 2 );
2999 ege_select_one_action_set_tooltip_column( act, 1 );
3001 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3002 ege_select_one_action_set_active( act, mode );
3003 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3005 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3006 }
3008 guint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3010 {
3011 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3012 ege_output_action_set_use_markup( act, TRUE );
3013 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3014 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3015 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3016 g_object_set_data( holder, "tweak_channels_label", act);
3017 }
3019 {
3020 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3021 _("Hue"),
3022 _("In color mode, act on objects' hue"),
3023 NULL,
3024 Inkscape::ICON_SIZE_DECORATION );
3025 g_object_set( act, "short_label", _("H"), NULL );
3026 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3027 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3028 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doh", 1 ) );
3029 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3030 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3031 g_object_set_data( holder, "tweak_doh", act);
3032 }
3033 {
3034 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3035 _("Saturation"),
3036 _("In color mode, act on objects' saturation"),
3037 NULL,
3038 Inkscape::ICON_SIZE_DECORATION );
3039 g_object_set( act, "short_label", _("S"), NULL );
3040 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3041 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3042 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dos", 1 ) );
3043 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3044 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3045 g_object_set_data( holder, "tweak_dos", act );
3046 }
3047 {
3048 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3049 _("Lightness"),
3050 _("In color mode, act on objects' lightness"),
3051 NULL,
3052 Inkscape::ICON_SIZE_DECORATION );
3053 g_object_set( act, "short_label", _("L"), NULL );
3054 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3055 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3056 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dol", 1 ) );
3057 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3058 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3059 g_object_set_data( holder, "tweak_dol", act );
3060 }
3061 {
3062 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3063 _("Opacity"),
3064 _("In color mode, act on objects' opacity"),
3065 NULL,
3066 Inkscape::ICON_SIZE_DECORATION );
3067 g_object_set( act, "short_label", _("O"), NULL );
3068 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3069 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3070 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doo", 1 ) );
3071 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3072 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3073 g_object_set_data( holder, "tweak_doo", act );
3074 }
3076 { /* Fidelity */
3077 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3078 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3079 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3080 _("Fidelity"), _("Fidelity:"),
3081 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3082 "tools.tweak", "fidelity", 50,
3083 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3084 1, 100, 1.0, 10.0,
3085 labels, values, G_N_ELEMENTS(labels),
3086 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3087 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3088 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3089 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3090 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3091 g_object_set_data( holder, "tweak_fidelity", eact );
3092 }
3095 /* Use Pressure button */
3096 {
3097 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3098 _("Pressure"),
3099 _("Use the pressure of the input device to alter the force of tweak action"),
3100 "use_pressure",
3101 Inkscape::ICON_SIZE_DECORATION );
3102 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3103 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3104 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
3105 }
3107 }
3110 //########################
3111 //## Calligraphy ##
3112 //########################
3114 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3115 {
3116 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
3117 }
3119 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3120 {
3121 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
3122 }
3124 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3125 {
3126 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
3127 }
3129 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3130 {
3131 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
3132 }
3134 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3135 {
3136 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
3137 }
3139 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3140 {
3141 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
3142 }
3144 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3145 {
3146 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
3147 }
3149 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3150 {
3151 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
3152 }
3154 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3155 {
3156 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3157 }
3159 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer /*data*/ )
3160 {
3161 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
3162 }
3164 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
3165 {
3166 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3168 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
3169 }
3171 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
3172 {
3173 // FIXME: make defaults settable via Inkscape Options
3174 struct KeyValue {
3175 char const *key;
3176 double value;
3177 } const key_values[] = {
3178 {"mass", 0.02},
3179 {"wiggle", 0.0},
3180 {"angle", 30.0},
3181 {"width", 15},
3182 {"thinning", 0.1},
3183 {"tremor", 0.0},
3184 {"flatness", 0.9},
3185 {"cap_rounding", 0.0}
3186 };
3188 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
3189 KeyValue const &kv = key_values[i];
3190 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
3191 if ( adj ) {
3192 gtk_adjustment_set_value(adj, kv.value);
3193 }
3194 }
3195 }
3198 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3199 {
3200 {
3201 EgeAdjustmentAction* calligraphy_angle = 0;
3203 {
3204 /* Width */
3205 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
3206 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3207 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
3208 _("Pen Width"), _("Width:"),
3209 _("The width of the calligraphic pen (relative to the visible canvas area)"),
3210 "tools.calligraphic", "width", 15,
3211 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
3212 1, 100, 1.0, 10.0,
3213 labels, values, G_N_ELEMENTS(labels),
3214 sp_ddc_width_value_changed, 0.01, 0, 100 );
3215 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3216 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3217 }
3219 {
3220 /* Thinning */
3221 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
3222 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
3223 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
3224 _("Stroke Thinning"), _("Thinning:"),
3225 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
3226 "tools.calligraphic", "thinning", 0.1,
3227 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3228 -1.0, 1.0, 0.01, 0.1,
3229 labels, values, G_N_ELEMENTS(labels),
3230 sp_ddc_velthin_value_changed, 0.01, 2);
3231 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3232 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3233 }
3235 {
3236 /* Angle */
3237 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
3238 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3239 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
3240 _("Pen Angle"), _("Angle:"),
3241 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
3242 "tools.calligraphic", "angle", 30,
3243 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
3244 -90.0, 90.0, 1.0, 10.0,
3245 labels, values, G_N_ELEMENTS(labels),
3246 sp_ddc_angle_value_changed, 1, 0 );
3247 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3248 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3249 calligraphy_angle = eact;
3250 }
3252 {
3253 /* Fixation */
3254 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
3255 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
3256 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
3257 _("Fixation"), _("Fixation:"),
3258 _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
3259 "tools.calligraphic", "flatness", 0.9,
3260 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3261 0.0, 1.0, 0.01, 0.1,
3262 labels, values, G_N_ELEMENTS(labels),
3263 sp_ddc_flatness_value_changed, 0.01, 2 );
3264 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3265 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3266 }
3268 {
3269 /* Cap Rounding */
3270 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
3271 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
3272 // TRANSLATORS: "cap" means "end" (both start and finish) here
3273 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
3274 _("Cap rounding"), _("Caps:"),
3275 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
3276 "tools.calligraphic", "cap_rounding", 0.0,
3277 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3278 0.0, 5.0, 0.01, 0.1,
3279 labels, values, G_N_ELEMENTS(labels),
3280 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
3281 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3282 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3283 }
3285 {
3286 /* Tremor */
3287 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
3288 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
3289 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
3290 _("Stroke Tremor"), _("Tremor:"),
3291 _("Increase to make strokes rugged and trembling"),
3292 "tools.calligraphic", "tremor", 0.0,
3293 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3294 0.0, 1.0, 0.01, 0.1,
3295 labels, values, G_N_ELEMENTS(labels),
3296 sp_ddc_tremor_value_changed, 0.01, 2 );
3298 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3299 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3300 }
3302 {
3303 /* Wiggle */
3304 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
3305 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
3306 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
3307 _("Pen Wiggle"), _("Wiggle:"),
3308 _("Increase to make the pen waver and wiggle"),
3309 "tools.calligraphic", "wiggle", 0.0,
3310 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3311 0.0, 1.0, 0.01, 0.1,
3312 labels, values, G_N_ELEMENTS(labels),
3313 sp_ddc_wiggle_value_changed, 0.01, 2 );
3314 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3315 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3316 }
3318 {
3319 /* Mass */
3320 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
3321 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
3322 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
3323 _("Pen Mass"), _("Mass:"),
3324 _("Increase to make the pen drag behind, as if slowed by inertia"),
3325 "tools.calligraphic", "mass", 0.02,
3326 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3327 0.0, 1.0, 0.01, 0.1,
3328 labels, values, G_N_ELEMENTS(labels),
3329 sp_ddc_mass_value_changed, 0.01, 2 );
3330 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3331 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3332 }
3335 /* Trace Background button */
3336 {
3337 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
3338 _("Trace Background"),
3339 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
3340 "trace_background",
3341 Inkscape::ICON_SIZE_DECORATION );
3342 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3343 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
3344 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
3345 }
3347 /* Use Pressure button */
3348 {
3349 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
3350 _("Pressure"),
3351 _("Use the pressure of the input device to alter the width of the pen"),
3352 "use_pressure",
3353 Inkscape::ICON_SIZE_DECORATION );
3354 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3355 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
3356 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
3357 }
3359 /* Use Tilt button */
3360 {
3361 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
3362 _("Tilt"),
3363 _("Use the tilt of the input device to alter the angle of the pen's nib"),
3364 "use_tilt",
3365 Inkscape::ICON_SIZE_DECORATION );
3366 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3367 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
3368 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3369 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3370 }
3372 /* Reset */
3373 {
3374 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
3375 _("Defaults"),
3376 _("Reset all parameters to defaults"),
3377 GTK_STOCK_CLEAR );
3378 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
3379 gtk_action_group_add_action( mainActions, act );
3380 gtk_action_set_sensitive( act, TRUE );
3381 }
3382 }
3383 }
3386 //########################
3387 //## Circle / Arc ##
3388 //########################
3390 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
3391 {
3392 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
3393 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
3395 if (v1 == 0 && v2 == 0) {
3396 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
3397 gtk_action_set_sensitive( ocb, FALSE );
3398 gtk_action_set_sensitive( make_whole, FALSE );
3399 }
3400 } else {
3401 gtk_action_set_sensitive( ocb, TRUE );
3402 gtk_action_set_sensitive( make_whole, TRUE );
3403 }
3404 }
3406 static void
3407 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
3408 {
3409 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3411 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3412 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
3413 }
3415 // quit if run by the attr_changed listener
3416 if (g_object_get_data( tbl, "freeze" )) {
3417 return;
3418 }
3420 // in turn, prevent listener from responding
3421 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3423 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
3425 bool modmade = false;
3426 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3427 items != NULL;
3428 items = items->next)
3429 {
3430 SPItem *item = SP_ITEM(items->data);
3432 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
3434 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
3435 SPArc *arc = SP_ARC(item);
3437 if (!strcmp(value_name, "start"))
3438 ge->start = (adj->value * M_PI)/ 180;
3439 else
3440 ge->end = (adj->value * M_PI)/ 180;
3442 sp_genericellipse_normalize(ge);
3443 ((SPObject *)arc)->updateRepr();
3444 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
3446 modmade = true;
3447 }
3448 }
3450 g_free(namespaced_name);
3452 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
3454 sp_arctb_sensitivize( tbl, adj->value, other->value );
3456 if (modmade) {
3457 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
3458 _("Arc: Change start/end"));
3459 }
3461 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3462 }
3465 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
3466 {
3467 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
3468 }
3470 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
3471 {
3472 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
3473 }
3475 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
3476 {
3477 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3478 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3479 if ( ege_select_one_action_get_active( act ) != 0 ) {
3480 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
3481 } else {
3482 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
3483 }
3484 }
3486 // quit if run by the attr_changed listener
3487 if (g_object_get_data( tbl, "freeze" )) {
3488 return;
3489 }
3491 // in turn, prevent listener from responding
3492 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3494 bool modmade = false;
3496 if ( ege_select_one_action_get_active(act) != 0 ) {
3497 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3498 items != NULL;
3499 items = items->next)
3500 {
3501 if (SP_IS_ARC((SPItem *) items->data)) {
3502 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3503 repr->setAttribute("sodipodi:open", "true");
3504 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3505 modmade = true;
3506 }
3507 }
3508 } else {
3509 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3510 items != NULL;
3511 items = items->next)
3512 {
3513 if (SP_IS_ARC((SPItem *) items->data)) {
3514 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3515 repr->setAttribute("sodipodi:open", NULL);
3516 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3517 modmade = true;
3518 }
3519 }
3520 }
3522 if (modmade) {
3523 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
3524 _("Arc: Change open/closed"));
3525 }
3527 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3528 }
3530 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
3531 {
3532 GtkAdjustment *adj;
3533 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
3534 gtk_adjustment_set_value(adj, 0.0);
3535 gtk_adjustment_value_changed(adj);
3537 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
3538 gtk_adjustment_set_value(adj, 0.0);
3539 gtk_adjustment_value_changed(adj);
3541 spinbutton_defocus( GTK_OBJECT(obj) );
3542 }
3544 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3545 gchar const */*old_value*/, gchar const */*new_value*/,
3546 bool /*is_interactive*/, gpointer data)
3547 {
3548 GObject *tbl = G_OBJECT(data);
3550 // quit if run by the _changed callbacks
3551 if (g_object_get_data( tbl, "freeze" )) {
3552 return;
3553 }
3555 // in turn, prevent callbacks from responding
3556 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3558 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
3559 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
3561 GtkAdjustment *adj1,*adj2;
3562 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
3563 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
3564 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
3565 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
3567 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
3569 char const *openstr = NULL;
3570 openstr = repr->attribute("sodipodi:open");
3571 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
3573 if (openstr) {
3574 ege_select_one_action_set_active( ocb, 1 );
3575 } else {
3576 ege_select_one_action_set_active( ocb, 0 );
3577 }
3579 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3580 }
3582 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
3583 NULL, /* child_added */
3584 NULL, /* child_removed */
3585 arc_tb_event_attr_changed,
3586 NULL, /* content_changed */
3587 NULL /* order_changed */
3588 };
3591 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3592 {
3593 int n_selected = 0;
3594 Inkscape::XML::Node *repr = NULL;
3596 purge_repr_listener( tbl, tbl );
3598 for (GSList const *items = selection->itemList();
3599 items != NULL;
3600 items = items->next)
3601 {
3602 if (SP_IS_ARC((SPItem *) items->data)) {
3603 n_selected++;
3604 repr = SP_OBJECT_REPR((SPItem *) items->data);
3605 }
3606 }
3608 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3610 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3611 if (n_selected == 0) {
3612 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3613 } else if (n_selected == 1) {
3614 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3615 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3617 if (repr) {
3618 g_object_set_data( tbl, "repr", repr );
3619 Inkscape::GC::anchor(repr);
3620 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
3621 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
3622 }
3623 } else {
3624 // FIXME: implement averaging of all parameters for multiple selected
3625 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3626 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3627 sp_arctb_sensitivize( tbl, 1, 0 );
3628 }
3629 }
3632 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3633 {
3634 EgeAdjustmentAction* eact = 0;
3637 {
3638 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
3639 ege_output_action_set_use_markup( act, TRUE );
3640 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3641 g_object_set_data( holder, "mode_action", act );
3642 }
3644 /* Start */
3645 {
3646 eact = create_adjustment_action( "ArcStartAction",
3647 _("Start"), _("Start:"),
3648 _("The angle (in degrees) from the horizontal to the arc's start point"),
3649 "tools.shapes.arc", "start", 0.0,
3650 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
3651 -360.0, 360.0, 1.0, 10.0,
3652 0, 0, 0,
3653 sp_arctb_start_value_changed);
3654 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3655 }
3657 /* End */
3658 {
3659 eact = create_adjustment_action( "ArcEndAction",
3660 _("End"), _("End:"),
3661 _("The angle (in degrees) from the horizontal to the arc's end point"),
3662 "tools.shapes.arc", "end", 0.0,
3663 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3664 -360.0, 360.0, 1.0, 10.0,
3665 0, 0, 0,
3666 sp_arctb_end_value_changed);
3667 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3668 }
3670 /* Segments / Pie checkbox */
3671 {
3672 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3674 GtkTreeIter iter;
3675 gtk_list_store_append( model, &iter );
3676 gtk_list_store_set( model, &iter,
3677 0, _("Closed arc"),
3678 1, _("Switch to segment (closed shape with two radii)"),
3679 2, "circle_closed_arc",
3680 -1 );
3682 gtk_list_store_append( model, &iter );
3683 gtk_list_store_set( model, &iter,
3684 0, _("Open Arc"),
3685 1, _("Switch to arc (unclosed shape)"),
3686 2, "circle_open_arc",
3687 -1 );
3689 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
3690 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3691 g_object_set_data( holder, "open_action", act );
3693 ege_select_one_action_set_appearance( act, "full" );
3694 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3695 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3696 ege_select_one_action_set_icon_column( act, 2 );
3697 ege_select_one_action_set_tooltip_column( act, 1 );
3699 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
3700 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
3701 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
3702 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
3703 }
3705 /* Make Whole */
3706 {
3707 InkAction* inky = ink_action_new( "ArcResetAction",
3708 _("Make whole"),
3709 _("Make the shape a whole ellipse, not arc or segment"),
3710 "reset_circle",
3711 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3712 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
3713 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3714 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3715 g_object_set_data( holder, "make_whole", inky );
3716 }
3718 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
3719 // sensitivize make whole and open checkbox
3720 {
3721 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
3722 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
3723 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
3724 }
3727 sigc::connection *connection = new sigc::connection(
3728 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
3729 );
3730 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3731 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3732 }
3737 // toggle button callbacks and updaters
3739 //########################
3740 //## Dropper ##
3741 //########################
3743 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
3744 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
3745 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
3746 if ( set_action ) {
3747 if ( gtk_toggle_action_get_active( act ) ) {
3748 gtk_action_set_sensitive( set_action, TRUE );
3749 } else {
3750 gtk_action_set_sensitive( set_action, FALSE );
3751 }
3752 }
3754 spinbutton_defocus(GTK_OBJECT(tbl));
3755 }
3757 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
3758 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3759 spinbutton_defocus(GTK_OBJECT(tbl));
3760 }
3763 /**
3764 * Dropper auxiliary toolbar construction and setup.
3765 *
3766 * TODO: Would like to add swatch of current color.
3767 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3768 * can drag and drop places. Will provide a nice mixing palette.
3769 */
3770 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3771 {
3772 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
3774 {
3775 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
3776 _("Pick alpha"),
3777 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
3778 "color_alpha_get",
3779 Inkscape::ICON_SIZE_DECORATION );
3780 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3781 g_object_set_data( holder, "pick_action", act );
3782 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
3783 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
3784 }
3786 {
3787 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
3788 _("Set alpha"),
3789 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
3790 "color_alpha_set",
3791 Inkscape::ICON_SIZE_DECORATION );
3792 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3793 g_object_set_data( holder, "set_action", act );
3794 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
3795 // make sure it's disabled if we're not picking alpha
3796 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
3797 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
3798 }
3799 }
3802 //########################
3803 //## Text Toolbox ##
3804 //########################
3805 /*
3806 static void
3807 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3808 {
3809 //Call back for letter sizing spinbutton
3810 }
3812 static void
3813 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3814 {
3815 //Call back for line height spinbutton
3816 }
3818 static void
3819 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3820 {
3821 //Call back for horizontal kerning spinbutton
3822 }
3824 static void
3825 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3826 {
3827 //Call back for vertical kerning spinbutton
3828 }
3830 static void
3831 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3832 {
3833 //Call back for letter rotation spinbutton
3834 }*/
3836 namespace {
3838 bool visible = false;
3840 void
3841 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
3842 {
3843 SPStyle *query =
3844 sp_style_new (SP_ACTIVE_DOCUMENT);
3846 int result_family =
3847 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3849 int result_style =
3850 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3852 int result_numbers =
3853 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3855 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3857 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3858 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3859 {
3860 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3862 if (repr)
3863 {
3864 sp_style_read_from_repr (query, repr);
3865 }
3866 else
3867 {
3868 return;
3869 }
3870 }
3872 if (query->text)
3873 {
3874 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3875 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3876 gtk_entry_set_text (GTK_ENTRY (entry), "");
3878 } else if (query->text->font_family.value) {
3880 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3881 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3883 Gtk::TreePath path;
3884 try {
3885 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3886 } catch (...) {
3887 return;
3888 }
3890 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3891 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3893 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3895 gtk_tree_selection_select_path (tselection, path.gobj());
3896 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3898 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3899 }
3901 //Size
3902 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3903 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3904 g_object_set_data (tbl, "size-block", gpointer(1));
3905 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3906 g_object_set_data (tbl, "size-block", gpointer(0));
3907 free (str);
3909 //Anchor
3910 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3911 {
3912 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3913 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3914 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3915 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3916 }
3917 else
3918 {
3919 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3920 {
3921 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3922 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3923 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3924 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3925 }
3926 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3927 {
3928 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3929 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3930 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3931 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3932 }
3933 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3934 {
3935 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3936 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3937 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3938 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3939 }
3940 }
3942 //Style
3943 {
3944 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3946 gboolean active = gtk_toggle_button_get_active (button);
3947 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3949 if (active != check)
3950 {
3951 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3952 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3953 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3954 }
3955 }
3957 {
3958 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3960 gboolean active = gtk_toggle_button_get_active (button);
3961 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3963 if (active != check)
3964 {
3965 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3966 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3967 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3968 }
3969 }
3971 //Orientation
3972 //locking both buttons, changing one affect all group (both)
3973 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3974 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3976 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3977 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3979 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3980 {
3981 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3982 }
3983 else
3984 {
3985 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3986 }
3987 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3988 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3989 }
3991 sp_style_unref(query);
3992 }
3994 void
3995 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
3996 {
3997 sp_text_toolbox_selection_changed (selection, tbl);
3998 }
4000 void
4001 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4002 {
4003 sp_text_toolbox_selection_changed (NULL, tbl);
4004 }
4006 void
4007 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4008 GObject *tbl)
4009 {
4010 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4011 GtkTreeModel *model = 0;
4012 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4013 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4014 GtkTreeIter iter;
4015 char *family = 0;
4017 (void)popdown;
4019 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4020 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4022 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
4023 return;
4024 }
4026 gtk_tree_model_get (model, &iter, 0, &family, -1);
4028 if (g_object_get_data (G_OBJECT (selection), "block"))
4029 {
4030 gtk_entry_set_text (GTK_ENTRY (entry), family);
4031 return;
4032 }
4034 gtk_entry_set_text (GTK_ENTRY (entry), family);
4036 SPStyle *query =
4037 sp_style_new (SP_ACTIVE_DOCUMENT);
4039 int result_numbers =
4040 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4042 SPCSSAttr *css = sp_repr_css_attr_new ();
4043 sp_repr_css_set_property (css, "font-family", family);
4045 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4046 if (result_numbers == QUERY_STYLE_NOTHING)
4047 {
4048 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4049 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
4050 }
4051 else
4052 {
4053 sp_desktop_set_style (desktop, css, true, true);
4054 }
4056 sp_style_unref(query);
4058 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4059 _("Text: Change font family"));
4060 sp_repr_css_attr_unref (css);
4061 free (family);
4062 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4064 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4065 }
4067 void
4068 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
4069 GObject *tbl)
4070 {
4071 const char *family = gtk_entry_get_text (entry);
4073 try {
4074 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
4075 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4076 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4077 gtk_tree_selection_select_path (selection, path.gobj());
4078 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4079 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4080 } catch (...) {
4081 if (family && strlen (family))
4082 {
4083 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4084 }
4085 }
4086 }
4088 void
4089 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
4090 gpointer data)
4091 {
4092 if (g_object_get_data (G_OBJECT (button), "block")) return;
4093 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
4094 int prop = GPOINTER_TO_INT(data);
4096 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4097 SPCSSAttr *css = sp_repr_css_attr_new ();
4099 switch (prop)
4100 {
4101 case 0:
4102 {
4103 sp_repr_css_set_property (css, "text-anchor", "start");
4104 sp_repr_css_set_property (css, "text-align", "start");
4105 break;
4106 }
4107 case 1:
4108 {
4109 sp_repr_css_set_property (css, "text-anchor", "middle");
4110 sp_repr_css_set_property (css, "text-align", "center");
4111 break;
4112 }
4114 case 2:
4115 {
4116 sp_repr_css_set_property (css, "text-anchor", "end");
4117 sp_repr_css_set_property (css, "text-align", "end");
4118 break;
4119 }
4121 case 3:
4122 {
4123 sp_repr_css_set_property (css, "text-anchor", "start");
4124 sp_repr_css_set_property (css, "text-align", "justify");
4125 break;
4126 }
4127 }
4129 SPStyle *query =
4130 sp_style_new (SP_ACTIVE_DOCUMENT);
4131 int result_numbers =
4132 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4134 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4135 if (result_numbers == QUERY_STYLE_NOTHING)
4136 {
4137 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4138 }
4140 sp_style_unref(query);
4142 sp_desktop_set_style (desktop, css, true, true);
4143 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4144 _("Text: Change alignment"));
4145 sp_repr_css_attr_unref (css);
4147 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4148 }
4150 void
4151 sp_text_toolbox_style_toggled (GtkToggleButton *button,
4152 gpointer data)
4153 {
4154 if (g_object_get_data (G_OBJECT (button), "block")) return;
4156 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4157 SPCSSAttr *css = sp_repr_css_attr_new ();
4158 int prop = GPOINTER_TO_INT(data);
4159 bool active = gtk_toggle_button_get_active (button);
4162 switch (prop)
4163 {
4164 case 0:
4165 {
4166 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
4167 break;
4168 }
4170 case 1:
4171 {
4172 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
4173 break;
4174 }
4175 }
4177 SPStyle *query =
4178 sp_style_new (SP_ACTIVE_DOCUMENT);
4179 int result_numbers =
4180 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4182 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4183 if (result_numbers == QUERY_STYLE_NOTHING)
4184 {
4185 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4186 }
4188 sp_style_unref(query);
4190 sp_desktop_set_style (desktop, css, true, true);
4191 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4192 _("Text: Change font style"));
4193 sp_repr_css_attr_unref (css);
4195 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4196 }
4198 void
4199 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
4200 gpointer data)
4201 {
4202 if (g_object_get_data (G_OBJECT (button), "block")) {
4203 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4204 return;
4205 }
4207 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4208 SPCSSAttr *css = sp_repr_css_attr_new ();
4209 int prop = GPOINTER_TO_INT(data);
4211 switch (prop)
4212 {
4213 case 0:
4214 {
4215 sp_repr_css_set_property (css, "writing-mode", "lr");
4216 break;
4217 }
4219 case 1:
4220 {
4221 sp_repr_css_set_property (css, "writing-mode", "tb");
4222 break;
4223 }
4224 }
4226 SPStyle *query =
4227 sp_style_new (SP_ACTIVE_DOCUMENT);
4228 int result_numbers =
4229 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4231 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4232 if (result_numbers == QUERY_STYLE_NOTHING)
4233 {
4234 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4235 }
4237 sp_desktop_set_style (desktop, css, true, true);
4238 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4239 _("Text: Change orientation"));
4240 sp_repr_css_attr_unref (css);
4242 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4243 }
4245 gboolean
4246 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, gpointer /*data*/)
4247 {
4248 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4249 if (!desktop) return FALSE;
4251 switch (get_group0_keyval (event)) {
4252 case GDK_Escape: // defocus
4253 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4254 return TRUE; // I consumed the event
4255 break;
4256 case GDK_Return: // defocus
4257 case GDK_KP_Enter:
4258 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4259 return TRUE; // I consumed the event
4260 break;
4261 }
4262 return FALSE;
4263 }
4265 gboolean
4266 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4267 {
4268 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4269 if (!desktop) return FALSE;
4271 switch (get_group0_keyval (event)) {
4272 case GDK_Escape: // defocus
4273 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4274 sp_text_toolbox_selection_changed (NULL, tbl); // update
4275 return TRUE; // I consumed the event
4276 break;
4277 }
4278 return FALSE;
4279 }
4281 gboolean
4282 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
4283 {
4284 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4285 if (!desktop) return FALSE;
4287 switch (get_group0_keyval (event)) {
4288 case GDK_KP_Enter:
4289 case GDK_Return:
4290 case GDK_Escape: // defocus
4291 gtk_widget_hide (w);
4292 visible = false;
4293 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4294 return TRUE; // I consumed the event
4295 break;
4296 }
4297 return FALSE;
4298 }
4301 void
4302 sp_text_toolbox_size_changed (GtkComboBox *cbox,
4303 GObject *tbl)
4304 {
4305 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4307 if (g_object_get_data (tbl, "size-block")) return;
4309 #if GTK_CHECK_VERSION(2,6,0)
4310 char *text = gtk_combo_box_get_active_text (cbox);
4311 #else // GTK_CHECK_VERSION(2,6,0)
4312 GtkTreeModel *model = gtk_combo_box_get_model (cbox);
4313 GtkTreeIter iter;
4314 char *text = NULL;
4316 if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
4317 gtk_tree_model_get (model, &iter, 0, &text, -1);
4318 #endif // GTK_CHECK_VERSION(2,6,0)
4320 SPCSSAttr *css = sp_repr_css_attr_new ();
4321 sp_repr_css_set_property (css, "font-size", text);
4322 free (text);
4324 SPStyle *query =
4325 sp_style_new (SP_ACTIVE_DOCUMENT);
4326 int result_numbers =
4327 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4329 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4330 if (result_numbers == QUERY_STYLE_NOTHING)
4331 {
4332 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4333 }
4335 sp_style_unref(query);
4337 sp_desktop_set_style (desktop, css, true, true);
4338 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
4339 _("Text: Change font size"));
4340 sp_repr_css_attr_unref (css);
4343 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
4344 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4345 }
4347 void
4348 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
4349 GObject *tbl)
4350 {
4351 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4352 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4353 int x, y;
4355 if (!visible)
4356 {
4357 gdk_window_get_origin (widget->window, &x, &y);
4358 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
4359 gtk_widget_show_all (popdown);
4361 gdk_pointer_grab (widget->window, TRUE,
4362 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
4363 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
4364 GDK_POINTER_MOTION_MASK),
4365 NULL, NULL, GDK_CURRENT_TIME);
4367 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
4369 visible = true;
4370 }
4371 else
4372 {
4373 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4374 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4375 gtk_widget_hide (popdown);
4376 visible = false;
4377 }
4378 }
4380 gboolean
4381 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
4382 GdkEventFocus */*event*/,
4383 GObject */*tbl*/)
4384 {
4385 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
4386 return FALSE;
4387 }
4389 gboolean
4390 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
4391 GdkEventFocus */*event*/,
4392 GObject */*tbl*/)
4393 {
4394 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4396 gtk_widget_hide (popdown);
4397 visible = false;
4398 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4399 return TRUE;
4400 }
4402 void
4403 cell_data_func (GtkTreeViewColumn */*column*/,
4404 GtkCellRenderer *cell,
4405 GtkTreeModel *tree_model,
4406 GtkTreeIter *iter,
4407 gpointer /*data*/)
4408 {
4409 char *family,
4410 *family_escaped,
4411 *sample_escaped;
4413 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
4415 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
4417 family_escaped = g_markup_escape_text (family, -1);
4418 sample_escaped = g_markup_escape_text (sample, -1);
4420 std::stringstream markup;
4421 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
4422 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
4424 free (family);
4425 free (family_escaped);
4426 free (sample_escaped);
4427 }
4429 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
4430 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
4431 if (completion) {
4432 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
4433 g_object_unref (completion);
4434 }
4435 }
4437 GtkWidget*
4438 sp_text_toolbox_new (SPDesktop *desktop)
4439 {
4440 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
4442 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4443 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4445 GtkTooltips *tt = gtk_tooltips_new();
4446 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4448 ////////////Family
4449 //Window
4450 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4451 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4453 //Entry
4454 GtkWidget *entry = gtk_entry_new ();
4455 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4456 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4457 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4458 gtk_entry_completion_set_text_column (completion, 0);
4459 gtk_entry_completion_set_minimum_key_length (completion, 1);
4460 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4461 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4462 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4463 aux_toolbox_space (tbl, 1);
4464 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
4465 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
4467 //Button
4468 GtkWidget *button = gtk_button_new ();
4469 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
4470 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
4472 //Popdown
4473 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
4474 GtkWidget *treeview = gtk_tree_view_new ();
4476 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4477 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
4478 gtk_tree_view_column_pack_start (column, cell, FALSE);
4479 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
4480 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
4481 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4483 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
4484 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
4485 #if GTK_CHECK_VERSION(2,6,0)
4486 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
4487 #endif // GTK_CHECK_VERSION(2,6,0)
4489 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
4491 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
4492 gtk_container_add (GTK_CONTAINER (sw), treeview);
4494 gtk_container_add (GTK_CONTAINER (window), sw);
4495 gtk_widget_set_size_request (window, 300, 450);
4497 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
4498 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
4499 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
4501 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
4503 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
4504 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
4506 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
4507 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
4509 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
4510 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
4511 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
4512 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
4513 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
4515 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
4516 aux_toolbox_space (tbl, 1);
4517 GtkWidget *box = gtk_event_box_new ();
4518 gtk_container_add (GTK_CONTAINER (box), image);
4519 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
4520 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
4521 GtkTooltips *tooltips = gtk_tooltips_new ();
4522 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
4523 gtk_widget_hide (GTK_WIDGET (box));
4524 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
4526 ////////////Size
4527 const char *sizes[] = {
4528 "4", "6", "8", "9", "10", "11", "12", "13", "14",
4529 "16", "18", "20", "22", "24", "28",
4530 "32", "36", "40", "48", "56", "64", "72", "144"
4531 };
4533 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
4534 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
4535 gtk_widget_set_size_request (cbox, 80, -1);
4536 aux_toolbox_space (tbl, 1);
4537 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
4538 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
4539 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
4540 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
4542 //spacer
4543 aux_toolbox_space (tbl, 4);
4544 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4546 ////////////Text anchor
4547 GtkWidget *group = gtk_radio_button_new (NULL);
4548 GtkWidget *row = gtk_hbox_new (FALSE, 4);
4549 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
4551 // left
4552 GtkWidget *rbutton = group;
4553 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4554 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4555 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4557 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4558 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
4559 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
4560 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
4562 // center
4563 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4564 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4565 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
4566 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4568 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4569 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
4570 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
4571 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
4573 // right
4574 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (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_RIGHT, 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-end", rbutton);
4581 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
4582 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
4584 // fill
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_FILL, 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-fill", rbutton);
4592 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
4593 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
4595 aux_toolbox_space (tbl, 1);
4596 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4598 //spacer
4599 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4601 ////////////Text style
4602 row = gtk_hbox_new (FALSE, 4);
4604 // bold
4605 rbutton = gtk_toggle_button_new ();
4606 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4607 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
4608 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4609 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
4611 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4612 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
4613 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
4615 // italic
4616 rbutton = gtk_toggle_button_new ();
4617 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4618 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
4619 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4620 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
4622 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4623 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
4624 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
4626 aux_toolbox_space (tbl, 1);
4627 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4629 //spacer
4630 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4632 ////////////Text orientation
4633 group = gtk_radio_button_new (NULL);
4634 row = gtk_hbox_new (FALSE, 4);
4635 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4637 // horizontal
4638 rbutton = group;
4639 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4640 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4641 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4642 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4644 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4645 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4646 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4648 // vertical
4649 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4650 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4651 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4652 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4653 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4655 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4656 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4657 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4658 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4661 //watch selection
4662 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4664 sigc::connection *c_selection_changed =
4665 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4666 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4667 pool->add_connection ("selection-changed", c_selection_changed);
4669 sigc::connection *c_selection_modified =
4670 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4671 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4672 pool->add_connection ("selection-modified", c_selection_modified);
4674 sigc::connection *c_subselection_changed =
4675 new sigc::connection (desktop->connectToolSubselectionChanged
4676 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4677 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4679 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4682 #if 0
4683 // horizontal
4684 {
4685 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
4686 GtkWidget *b = group = gtk_radio_button_new (NULL);
4687 gtk_container_add (GTK_CONTAINER (b), px);
4688 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
4689 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4690 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4691 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4692 }
4694 // vertical
4695 {
4696 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
4697 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4698 gtk_container_add (GTK_CONTAINER (b), px);
4699 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
4700 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4701 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4702 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4703 }
4705 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4707 // letter spacing
4708 {
4709 {
4710 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
4711 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4712 gtk_container_add (GTK_CONTAINER (hb), image);
4713 gtk_widget_show(image);
4714 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4715 }
4717 {
4718 GtkWidget *hb = sp_tb_spinbutton((""), _("Spacing between letters"),
4719 "tools.text", "letter_spacing", 0.0,
4720 us, tbl, FALSE, NULL,
4721 -1000.0, 1000.0, 0.1, 0.1,
4722 sp_text_letter_changed, 0.1, 1);
4723 gtk_widget_set_size_request (hb, 45, 6);
4724 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4725 }
4726 }
4728 // line spacing
4729 {
4730 {
4731 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
4732 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4733 gtk_container_add (GTK_CONTAINER (hb), image);
4734 gtk_widget_show(image);
4735 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4736 }
4738 {
4739 GtkWidget *hb = sp_tb_spinbutton((""), _("Spacing between lines"),
4740 "tools.text", "line_spacing", 0,
4741 us, tbl, FALSE, NULL,
4742 -1000.0, 1000.0, 0.1, 0.1,
4743 sp_text_line_changed, 0.1, 1);
4744 gtk_widget_set_size_request (hb, 45, 0);
4745 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
4746 }
4747 }
4749 {
4750 // horizontal kerning/vertical kerning units menu: create
4751 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
4752 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
4753 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
4755 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4757 // horizontal kerning
4758 {
4759 {
4760 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
4761 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4762 gtk_container_add (GTK_CONTAINER (hb), image);
4763 gtk_widget_show(image);
4764 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4765 }
4767 {
4768 GtkWidget *hb = sp_tb_spinbutton((""), _("Horizontal kerning"),
4769 "tools.text", "horizontal_kerning", 0,
4770 us, tbl, FALSE, NULL,
4771 -100.00, 100.00, 0.01, 0.1,
4772 sp_text_horiz_kern_changed);
4773 gtk_widget_set_size_request (hb, 45, 0);
4774 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4775 }
4776 }
4778 // vertical kerning
4779 {
4780 {
4781 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
4782 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4783 gtk_container_add (GTK_CONTAINER (hb), image);
4784 gtk_widget_show(image);
4785 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4786 }
4788 {
4789 GtkWidget *hb = sp_tb_spinbutton((""), _("Vertical kerning"),
4790 "tools.text", "vertical_kerning", 0,
4791 us, tbl, FALSE, NULL,
4792 -100.00, 100.00, 0.01, 0.1,
4793 sp_text_vert_kern_changed);
4794 gtk_widget_set_size_request (hb, 45, 0);
4795 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
4796 }
4797 }
4799 // add the units menu
4800 gtk_widget_show(us);
4801 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
4802 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
4803 }
4805 // letter rotation
4806 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4807 {
4808 {
4809 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
4810 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4811 gtk_container_add (GTK_CONTAINER (hb), image);
4812 gtk_widget_show(image);
4813 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4814 }
4815 {
4816 GtkWidget *hb = sp_tb_spinbutton((""), _("Letter rotation"),
4817 "tools.text", "letter_rotation", 0,
4818 us, tbl, FALSE, NULL,
4819 -180.0, 180.0, 0.1, 0.1,
4820 sp_text_letter_rotation_changed, 0.1, 1);
4821 gtk_widget_set_size_request (hb, 45, 0);
4822 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4823 }
4824 // rotation degree label
4825 {
4826 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4827 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4828 }
4829 }
4831 // Remove Manual Kerns
4832 {
4833 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4834 GtkWidget *button = gtk_button_new ();
4835 gtk_container_add (GTK_CONTAINER (button), px);
4836 gtk_widget_show(button);
4837 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4838 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4839 gtk_widget_set_sensitive(button, TRUE);
4840 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4841 }
4842 #endif
4844 gtk_widget_show_all (tbl);
4845 return tbl;
4847 } // end of sp_text_toolbox_new()
4849 }//<unnamed> namespace
4852 //#########################
4853 //## Connector ##
4854 //#########################
4856 static void sp_connector_path_set_avoid(void)
4857 {
4858 cc_selection_set_avoid(true);
4859 }
4862 static void sp_connector_path_set_ignore(void)
4863 {
4864 cc_selection_set_avoid(false);
4865 }
4869 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4870 {
4871 // quit if run by the _changed callbacks
4872 if (g_object_get_data( tbl, "freeze" )) {
4873 return;
4874 }
4876 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4877 SPDocument *doc = sp_desktop_document(desktop);
4879 if (!sp_document_get_undo_sensitive(doc))
4880 {
4881 return;
4882 }
4884 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4886 if ( repr->attribute("inkscape:connector-spacing") ) {
4887 gdouble priorValue = gtk_adjustment_get_value(adj);
4888 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4889 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4890 return;
4891 }
4892 } else if ( adj->value == defaultConnSpacing ) {
4893 return;
4894 }
4896 // in turn, prevent callbacks from responding
4897 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4899 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4900 SP_OBJECT(desktop->namedview)->updateRepr();
4902 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4903 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4904 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4905 NR::Matrix m = NR::identity();
4906 avoid_item_move(&m, item);
4907 }
4909 if (items) {
4910 g_slist_free(items);
4911 }
4913 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4914 _("Change connector spacing"));
4916 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4918 spinbutton_defocus(GTK_OBJECT(tbl));
4919 }
4921 static void sp_connector_graph_layout(void)
4922 {
4923 if (!SP_ACTIVE_DESKTOP) return;
4925 // hack for clones, see comment in align-and-distribute.cpp
4926 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4927 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4929 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4931 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4933 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4934 }
4936 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4937 {
4938 if ( gtk_toggle_action_get_active( act ) ) {
4939 prefs_set_string_attribute("tools.connector", "directedlayout",
4940 "true");
4941 } else {
4942 prefs_set_string_attribute("tools.connector", "directedlayout",
4943 "false");
4944 }
4945 }
4947 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4948 {
4949 if ( gtk_toggle_action_get_active( act ) ) {
4950 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4951 "true");
4952 } else {
4953 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4954 "false");
4955 }
4956 }
4959 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4960 {
4961 prefs_set_double_attribute("tools.connector", "length", adj->value);
4962 spinbutton_defocus(GTK_OBJECT(tbl));
4963 }
4965 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4966 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
4967 bool /*is_interactive*/, gpointer data)
4968 {
4969 GtkWidget *tbl = GTK_WIDGET(data);
4971 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4972 return;
4973 }
4974 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4975 return;
4976 }
4978 GtkAdjustment *adj = (GtkAdjustment*)
4979 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4980 gdouble spacing = defaultConnSpacing;
4981 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4983 gtk_adjustment_set_value(adj, spacing);
4984 }
4987 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4988 NULL, /* child_added */
4989 NULL, /* child_removed */
4990 connector_tb_event_attr_changed,
4991 NULL, /* content_changed */
4992 NULL /* order_changed */
4993 };
4996 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
4997 {
4998 {
4999 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
5000 _("Avoid"),
5001 _("Make connectors avoid selected objects"),
5002 "connector_avoid",
5003 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5004 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
5005 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5006 }
5008 {
5009 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
5010 _("Ignore"),
5011 _("Make connectors ignore selected objects"),
5012 "connector_ignore",
5013 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5014 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
5015 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5016 }
5018 EgeAdjustmentAction* eact = 0;
5020 // Spacing spinbox
5021 eact = create_adjustment_action( "ConnectorSpacingAction",
5022 _("Connector Spacing"), _("Spacing:"),
5023 _("The amount of space left around objects by auto-routing connectors"),
5024 "tools.connector", "spacing", defaultConnSpacing,
5025 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
5026 0, 100, 1.0, 10.0,
5027 0, 0, 0,
5028 connector_spacing_changed, 1, 0 );
5029 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5031 // Graph (connector network) layout
5032 {
5033 InkAction* inky = ink_action_new( "ConnectorGraphAction",
5034 _("Graph"),
5035 _("Nicely arrange selected connector network"),
5036 "graph_layout",
5037 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5038 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
5039 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5040 }
5042 // Default connector length spinbox
5043 eact = create_adjustment_action( "ConnectorLengthAction",
5044 _("Connector Length"), _("Length:"),
5045 _("Ideal length for connectors when layout is applied"),
5046 "tools.connector", "length", 100,
5047 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
5048 10, 1000, 10.0, 100.0,
5049 0, 0, 0,
5050 connector_length_changed, 1, 0 );
5051 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5054 // Directed edges toggle button
5055 {
5056 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
5057 _("Downwards"),
5058 _("Make connectors with end-markers (arrows) point downwards"),
5059 "directed_graph",
5060 Inkscape::ICON_SIZE_DECORATION );
5061 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5063 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
5064 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5065 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5067 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
5068 }
5070 // Avoid overlaps toggle button
5071 {
5072 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
5073 _("Remove overlaps"),
5074 _("Do not allow overlapping shapes"),
5075 "remove_overlaps",
5076 Inkscape::ICON_SIZE_DECORATION );
5077 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5079 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
5080 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5081 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5083 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
5084 }
5086 // Code to watch for changes to the connector-spacing attribute in
5087 // the XML.
5088 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5089 g_assert(repr != NULL);
5091 purge_repr_listener( holder, holder );
5093 if (repr) {
5094 g_object_set_data( holder, "repr", repr );
5095 Inkscape::GC::anchor(repr);
5096 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
5097 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
5098 }
5099 } // end of sp_connector_toolbox_prep()
5102 //#########################
5103 //## Paintbucket ##
5104 //#########################
5106 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
5107 {
5108 gint channels = ege_select_one_action_get_active( act );
5109 flood_channels_set_channels( channels );
5110 }
5112 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
5113 {
5114 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
5115 }
5117 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
5118 {
5119 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
5120 }
5122 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
5123 {
5124 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
5125 SPUnit const *unit = tracker->getActiveUnit();
5127 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
5129 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
5130 }
5132 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
5133 {
5134 // FIXME: make defaults settable via Inkscape Options
5135 struct KeyValue {
5136 char const *key;
5137 double value;
5138 } const key_values[] = {
5139 {"threshold", 15},
5140 {"offset", 0.0}
5141 };
5143 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
5144 KeyValue const &kv = key_values[i];
5145 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
5146 if ( adj ) {
5147 gtk_adjustment_set_value(adj, kv.value);
5148 }
5149 }
5151 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
5152 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
5153 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
5154 ege_select_one_action_set_active( autogap_action, 0 );
5155 }
5157 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5158 {
5159 EgeAdjustmentAction* eact = 0;
5161 {
5162 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5164 GList* items = 0;
5165 gint count = 0;
5166 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
5167 {
5168 GtkTreeIter iter;
5169 gtk_list_store_append( model, &iter );
5170 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5171 count++;
5172 }
5173 g_list_free( items );
5174 items = 0;
5175 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
5176 g_object_set( act1, "short_label", _("Fill by:"), NULL );
5177 ege_select_one_action_set_appearance( act1, "compact" );
5178 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
5179 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
5180 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
5181 g_object_set_data( holder, "channels_action", act1 );
5182 }
5184 // Spacing spinbox
5185 {
5186 eact = create_adjustment_action(
5187 "ThresholdAction",
5188 _("Fill Threshold"), _("Threshold:"),
5189 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
5190 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
5191 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
5192 0, 0, 0,
5193 paintbucket_threshold_changed, 1, 0 );
5195 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5196 }
5198 // Create the units menu.
5199 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
5200 tracker->setActiveUnit(sp_unit_get_by_abbreviation(prefs_get_string_attribute("tools.paintbucket", "offsetunits")));
5201 g_object_set_data( holder, "tracker", tracker );
5202 {
5203 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
5204 gtk_action_group_add_action( mainActions, act );
5205 }
5207 // Offset spinbox
5208 {
5209 eact = create_adjustment_action(
5210 "OffsetAction",
5211 _("Grow/shrink by"), _("Grow/shrink by:"),
5212 _("The amount to grow (positive) or shrink (negative) the created fill path"),
5213 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
5214 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
5215 0, 0, 0,
5216 paintbucket_offset_changed, 1, 2);
5217 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
5219 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5220 }
5222 /* Auto Gap */
5223 {
5224 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5226 GList* items = 0;
5227 gint count = 0;
5228 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
5229 {
5230 GtkTreeIter iter;
5231 gtk_list_store_append( model, &iter );
5232 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5233 count++;
5234 }
5235 g_list_free( items );
5236 items = 0;
5237 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
5238 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
5239 ege_select_one_action_set_appearance( act2, "compact" );
5240 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
5241 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
5242 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
5243 g_object_set_data( holder, "autogap_action", act2 );
5244 }
5246 /* Reset */
5247 {
5248 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
5249 _("Defaults"),
5250 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
5251 GTK_STOCK_CLEAR );
5252 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
5253 gtk_action_group_add_action( mainActions, act );
5254 gtk_action_set_sensitive( act, TRUE );
5255 }
5257 }
5259 /*
5260 Local Variables:
5261 mode:c++
5262 c-file-style:"stroustrup"
5263 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
5264 indent-tabs-mode:nil
5265 fill-column:99
5266 End:
5267 */
5268 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :