1 /** \file
2 * Controls bars for some of Inkscape's tools
3 * (for some tools, they are in their own files)
4 */
6 /*
7 *
8 * Authors:
9 * MenTaLguY <mental@rydia.net>
10 * Lauris Kaplinski <lauris@kaplinski.com>
11 * bulia byak <buliabyak@users.sf.net>
12 * Frank Felfe <innerspace@iname.com>
13 * John Cliff <simarilius@yahoo.com>
14 * David Turner <novalis@gnu.org>
15 * Josh Andler <scislac@scislac.com>
16 * Jon A. Cruz <jon@joncruz.org>
17 *
18 * Copyright (C) 2004 David Turner
19 * Copyright (C) 2003 MenTaLguY
20 * Copyright (C) 1999-2006 authors
21 * Copyright (C) 2001-2002 Ximian, Inc.
22 *
23 * Released under GNU GPL, read the file 'COPYING' for more information
24 */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 #include <gtkmm.h>
31 #include <gtk/gtk.h>
32 #include <iostream>
33 #include <sstream>
35 #include "widgets/button.h"
36 #include "widgets/widget-sizes.h"
37 #include "widgets/spw-utilities.h"
38 #include "widgets/spinbutton-events.h"
39 #include "dialogs/text-edit.h"
41 #include "ui/widget/style-swatch.h"
43 #include "prefs-utils.h"
44 #include "verbs.h"
45 #include "sp-namedview.h"
46 #include "desktop.h"
47 #include "desktop-handles.h"
48 #include "xml/repr.h"
49 #include "xml/node-event-vector.h"
50 #include <glibmm/i18n.h>
51 #include "helper/unit-menu.h"
52 #include "helper/units.h"
54 #include "inkscape.h"
55 #include "conn-avoid-ref.h"
58 #include "select-toolbar.h"
59 #include "gradient-toolbar.h"
61 #include "connector-context.h"
62 #include "node-context.h"
63 #include "shape-editor.h"
64 #include "tweak-context.h"
65 #include "sp-rect.h"
66 #include "box3d.h"
67 #include "box3d-context.h"
68 #include "sp-star.h"
69 #include "sp-spiral.h"
70 #include "sp-ellipse.h"
71 #include "sp-text.h"
72 #include "sp-flowtext.h"
73 #include "style.h"
74 #include "selection.h"
75 #include "selection-chemistry.h"
76 #include "document-private.h"
77 #include "desktop-style.h"
78 #include "../libnrtype/font-lister.h"
79 #include "../libnrtype/font-instance.h"
80 #include "../connection-pool.h"
81 #include "../prefs-utils.h"
82 #include "../inkscape-stock.h"
83 #include "icon.h"
84 #include "graphlayout/graphlayout.h"
86 #include "mod360.h"
88 #include "toolbox.h"
90 #include "flood-context.h"
92 #include "ink-action.h"
93 #include "ege-adjustment-action.h"
94 #include "ege-output-action.h"
95 #include "ege-select-one-action.h"
96 #include "helper/unit-tracker.h"
98 using Inkscape::UnitTracker;
100 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
101 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
103 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
104 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
105 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
116 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
122 static struct {
123 gchar const *type_name;
124 gchar const *data_name;
125 sp_verb_t verb;
126 sp_verb_t doubleclick_verb;
127 } const tools[] = {
128 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
129 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
130 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
131 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
132 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
133 { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
134 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
135 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
136 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
137 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
138 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
139 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
140 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
141 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
142 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
143 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
144 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
145 { NULL, NULL, 0, 0 }
146 };
148 static struct {
149 gchar const *type_name;
150 gchar const *data_name;
151 GtkWidget *(*create_func)(SPDesktop *desktop);
152 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
153 gchar const *ui_name;
154 gint swatch_verb_id;
155 gchar const *swatch_tool;
156 gchar const *swatch_tip;
157 } const aux_toolboxes[] = {
158 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
159 SP_VERB_INVALID, 0, 0},
160 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
161 SP_VERB_INVALID, 0, 0},
162 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
163 SP_VERB_CONTEXT_TWEAK_PREFS, "tools.tweak", _("Color/opacity used for color tweaking")},
164 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
165 SP_VERB_INVALID, 0, 0},
166 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
167 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
168 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
169 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
170 { "Box3DContext", "3dbox_toolbox", 0, box3d_toolbox_prep, "3DBoxToolbar",
171 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
172 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
173 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
174 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
175 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
176 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
177 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
178 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
179 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
180 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
181 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
182 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
183 SP_VERB_INVALID, 0, 0},
184 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
185 SP_VERB_INVALID, 0, 0},
186 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
187 SP_VERB_INVALID, 0, 0},
188 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
189 SP_VERB_INVALID, 0, 0},
190 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
191 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
192 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
193 };
196 static gchar const * ui_descr =
197 "<ui>"
198 " <toolbar name='SelectToolbar'>"
199 " <toolitem action='EditSelectAll' />"
200 " <toolitem action='EditSelectAllInAllLayers' />"
201 " <toolitem action='EditDeselect' />"
202 " <separator />"
203 " <toolitem action='ObjectRotate90CCW' />"
204 " <toolitem action='ObjectRotate90' />"
205 " <toolitem action='ObjectFlipHorizontally' />"
206 " <toolitem action='ObjectFlipVertically' />"
207 " <separator />"
208 " <toolitem action='SelectionToBack' />"
209 " <toolitem action='SelectionLower' />"
210 " <toolitem action='SelectionRaise' />"
211 " <toolitem action='SelectionToFront' />"
212 " <separator />"
213 " <toolitem action='XAction' />"
214 " <toolitem action='YAction' />"
215 " <toolitem action='WidthAction' />"
216 " <toolitem action='LockAction' />"
217 " <toolitem action='HeightAction' />"
218 " <toolitem action='UnitsAction' />"
219 " <separator />"
220 " <toolitem action='transform_affect_label' />"
221 " <toolitem action='transform_stroke' />"
222 " <toolitem action='transform_corners' />"
223 " <toolitem action='transform_gradient' />"
224 " <toolitem action='transform_pattern' />"
225 " </toolbar>"
227 " <toolbar name='NodeToolbar'>"
228 " <toolitem action='NodeInsertAction' />"
229 " <toolitem action='NodeDeleteAction' />"
230 " <separator />"
231 " <toolitem action='NodeJoinAction' />"
232 " <toolitem action='NodeJoinSegmentAction' />"
233 " <toolitem action='NodeDeleteSegmentAction' />"
234 " <toolitem action='NodeBreakAction' />"
235 " <separator />"
236 " <toolitem action='NodeCuspAction' />"
237 " <toolitem action='NodeSmoothAction' />"
238 " <toolitem action='NodeSymmetricAction' />"
239 " <separator />"
240 " <toolitem action='NodeLineAction' />"
241 " <toolitem action='NodeCurveAction' />"
242 " <separator />"
243 " <toolitem action='ObjectToPath' />"
244 " <toolitem action='StrokeToPath' />"
245 " <separator />"
246 " <toolitem action='NodesShowHandlesAction' />"
247 " <separator />"
248 " <toolitem action='EditNextLPEParameterAction' />"
249 " <separator />"
250 " <toolitem action='NodeXAction' />"
251 " <toolitem action='NodeYAction' />"
252 " <toolitem action='NodeUnitsAction' />"
253 " </toolbar>"
255 " <toolbar name='TweakToolbar'>"
256 " <toolitem action='TweakWidthAction' />"
257 " <separator />"
258 " <toolitem action='TweakForceAction' />"
259 " <toolitem action='TweakPressureAction' />"
260 " <separator />"
261 " <toolitem action='TweakModeAction' />"
262 " <separator />"
263 " <toolitem action='TweakFidelityAction' />"
264 " <separator />"
265 " <toolitem action='TweakChannelsLabel' />"
266 " <toolitem action='TweakDoH' />"
267 " <toolitem action='TweakDoS' />"
268 " <toolitem action='TweakDoL' />"
269 " <toolitem action='TweakDoO' />"
270 " </toolbar>"
272 " <toolbar name='ZoomToolbar'>"
273 " <toolitem action='ZoomIn' />"
274 " <toolitem action='ZoomOut' />"
275 " <separator />"
276 " <toolitem action='Zoom1:0' />"
277 " <toolitem action='Zoom1:2' />"
278 " <toolitem action='Zoom2:1' />"
279 " <separator />"
280 " <toolitem action='ZoomSelection' />"
281 " <toolitem action='ZoomDrawing' />"
282 " <toolitem action='ZoomPage' />"
283 " <toolitem action='ZoomPageWidth' />"
284 " <separator />"
285 " <toolitem action='ZoomPrev' />"
286 " <toolitem action='ZoomNext' />"
287 " </toolbar>"
289 " <toolbar name='StarToolbar'>"
290 " <separator />"
291 " <toolitem action='StarStateAction' />"
292 " <separator />"
293 " <toolitem action='FlatAction' />"
294 " <separator />"
295 " <toolitem action='MagnitudeAction' />"
296 " <toolitem action='SpokeAction' />"
297 " <toolitem action='RoundednessAction' />"
298 " <toolitem action='RandomizationAction' />"
299 " <separator />"
300 " <toolitem action='StarResetAction' />"
301 " </toolbar>"
303 " <toolbar name='RectToolbar'>"
304 " <toolitem action='RectStateAction' />"
305 " <toolitem action='RectWidthAction' />"
306 " <toolitem action='RectHeightAction' />"
307 " <toolitem action='RadiusXAction' />"
308 " <toolitem action='RadiusYAction' />"
309 " <toolitem action='RectUnitsAction' />"
310 " <separator />"
311 " <toolitem action='RectResetAction' />"
312 " </toolbar>"
314 " <toolbar name='3DBoxToolbar'>"
315 " <toolitem action='3DBoxPosAngleXAction' />"
316 " <toolitem action='3DBoxVPXAction' />"
317 " <separator />"
318 " <toolitem action='3DBoxPosAngleYAction' />"
319 " <toolitem action='3DBoxVPYAction' />"
320 " <separator />"
321 " <toolitem action='3DBoxPosAngleZAction' />"
322 " <toolitem action='3DBoxVPZAction' />"
323 " <separator />"
324 " </toolbar>"
326 " <toolbar name='SpiralToolbar'>"
327 " <toolitem action='SpiralStateAction' />"
328 " <toolitem action='SpiralRevolutionAction' />"
329 " <toolitem action='SpiralExpansionAction' />"
330 " <toolitem action='SpiralT0Action' />"
331 " <separator />"
332 " <toolitem action='SpiralResetAction' />"
333 " </toolbar>"
335 " <toolbar name='PenToolbar'>"
336 " </toolbar>"
338 " <toolbar name='PencilToolbar'>"
339 " </toolbar>"
341 " <toolbar name='CalligraphyToolbar'>"
342 " <separator />"
343 " <toolitem action='CalligraphyWidthAction' />"
344 " <toolitem action='PressureAction' />"
345 " <toolitem action='TraceAction' />"
346 " <toolitem action='ThinningAction' />"
347 " <separator />"
348 " <toolitem action='AngleAction' />"
349 " <toolitem action='TiltAction' />"
350 " <toolitem action='FixationAction' />"
351 " <separator />"
352 " <toolitem action='CapRoundingAction' />"
353 " <separator />"
354 " <toolitem action='TremorAction' />"
355 " <toolitem action='WiggleAction' />"
356 " <toolitem action='MassAction' />"
357 " <separator />"
358 " <toolitem action='CalligraphyResetAction' />"
359 " </toolbar>"
361 " <toolbar name='ArcToolbar'>"
362 " <toolitem action='ArcStateAction' />"
363 " <separator />"
364 " <toolitem action='ArcStartAction' />"
365 " <toolitem action='ArcEndAction' />"
366 " <separator />"
367 " <toolitem action='ArcOpenAction' />"
368 " <separator />"
369 " <toolitem action='ArcResetAction' />"
370 " <separator />"
371 " </toolbar>"
373 " <toolbar name='PaintbucketToolbar'>"
374 " <toolitem action='ChannelsAction' />"
375 " <separator />"
376 " <toolitem action='ThresholdAction' />"
377 " <separator />"
378 " <toolitem action='OffsetAction' />"
379 " <toolitem action='PaintbucketUnitsAction' />"
380 " <separator />"
381 " <toolitem action='AutoGapAction' />"
382 " <separator />"
383 " <toolitem action='PaintbucketResetAction' />"
384 " </toolbar>"
386 " <toolbar name='DropperToolbar'>"
387 " <toolitem action='DropperPickAlphaAction' />"
388 " <toolitem action='DropperSetAlphaAction' />"
389 " </toolbar>"
391 " <toolbar name='ConnectorToolbar'>"
392 " <toolitem action='ConnectorAvoidAction' />"
393 " <toolitem action='ConnectorIgnoreAction' />"
394 " <toolitem action='ConnectorSpacingAction' />"
395 " <toolitem action='ConnectorGraphAction' />"
396 " <toolitem action='ConnectorLengthAction' />"
397 " <toolitem action='ConnectorDirectedAction' />"
398 " <toolitem action='ConnectorOverlapAction' />"
399 " </toolbar>"
401 "</ui>"
402 ;
404 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
406 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
408 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
409 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
411 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
412 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
414 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
415 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
417 /* Global text entry widgets necessary for update */
418 /* GtkWidget *dropper_rgb_entry,
419 *dropper_opacity_entry ; */
420 // should be made a private member once this is converted to class
422 static void delete_connection(GObject */*obj*/, sigc::connection *connection) {
423 connection->disconnect();
424 delete connection;
425 }
427 static void purge_repr_listener( GObject* obj, GObject* tbl )
428 {
429 (void)obj;
430 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
431 if (oldrepr) { // remove old listener
432 sp_repr_remove_listener_by_data(oldrepr, tbl);
433 Inkscape::GC::release(oldrepr);
434 oldrepr = 0;
435 g_object_set_data( tbl, "repr", NULL );
436 }
437 }
439 GtkWidget *
440 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
441 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
442 Inkscape::UI::View::View *view, GtkTooltips *tt)
443 {
444 SPAction *action = verb->get_action(view);
445 if (!action) return NULL;
447 SPAction *doubleclick_action;
448 if (doubleclick_verb)
449 doubleclick_action = doubleclick_verb->get_action(view);
450 else
451 doubleclick_action = NULL;
453 /* fixme: Handle sensitive/unsensitive */
454 /* fixme: Implement sp_button_new_from_action */
455 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
456 gtk_widget_show(b);
457 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
459 return b;
460 }
462 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
463 Inkscape::UI::View::View *view, GtkTooltips *tt)
464 {
465 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
466 }
468 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
469 Inkscape::UI::View::View *view, GtkTooltips *tt)
470 {
471 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
472 }
475 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
476 {
477 SPAction* targetAction = SP_ACTION(user_data);
478 if ( targetAction ) {
479 sp_action_perform( targetAction, NULL );
480 }
481 }
483 static void sp_action_action_set_sensitive (SPAction */*action*/, unsigned int sensitive, void *data)
484 {
485 if ( data ) {
486 GtkAction* act = GTK_ACTION(data);
487 gtk_action_set_sensitive( act, sensitive );
488 }
489 }
491 static SPActionEventVector action_event_vector = {
492 {NULL},
493 NULL,
494 NULL,
495 sp_action_action_set_sensitive,
496 NULL,
497 NULL
498 };
500 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
501 {
502 GtkAction* act = 0;
504 SPAction* targetAction = verb->get_action(view);
505 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
506 act = GTK_ACTION(inky);
507 gtk_action_set_sensitive( act, targetAction->sensitive );
509 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
511 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
512 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
514 return act;
515 }
517 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
518 {
519 Inkscape::UI::View::View *view = desktop;
520 gint verbsToUse[] = {
521 // disabled until we have icons for them:
522 //find
523 //SP_VERB_EDIT_TILE,
524 //SP_VERB_EDIT_UNTILE,
525 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
526 SP_VERB_DIALOG_DISPLAY,
527 SP_VERB_DIALOG_FILL_STROKE,
528 SP_VERB_DIALOG_NAMEDVIEW,
529 SP_VERB_DIALOG_TEXT,
530 SP_VERB_DIALOG_XML_EDITOR,
531 SP_VERB_EDIT_CLONE,
532 SP_VERB_EDIT_COPY,
533 SP_VERB_EDIT_CUT,
534 SP_VERB_EDIT_DUPLICATE,
535 SP_VERB_EDIT_PASTE,
536 SP_VERB_EDIT_REDO,
537 SP_VERB_EDIT_UNDO,
538 SP_VERB_EDIT_UNLINK_CLONE,
539 SP_VERB_FILE_EXPORT,
540 SP_VERB_FILE_IMPORT,
541 SP_VERB_FILE_NEW,
542 SP_VERB_FILE_OPEN,
543 SP_VERB_FILE_PRINT,
544 SP_VERB_FILE_SAVE,
545 SP_VERB_OBJECT_TO_CURVE,
546 SP_VERB_SELECTION_GROUP,
547 SP_VERB_SELECTION_OUTLINE,
548 SP_VERB_SELECTION_UNGROUP,
549 SP_VERB_ZOOM_1_1,
550 SP_VERB_ZOOM_1_2,
551 SP_VERB_ZOOM_2_1,
552 SP_VERB_ZOOM_DRAWING,
553 SP_VERB_ZOOM_IN,
554 SP_VERB_ZOOM_NEXT,
555 SP_VERB_ZOOM_OUT,
556 SP_VERB_ZOOM_PAGE,
557 SP_VERB_ZOOM_PAGE_WIDTH,
558 SP_VERB_ZOOM_PREV,
559 SP_VERB_ZOOM_SELECTION,
560 };
562 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
563 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
565 static std::map<SPDesktop*, GtkActionGroup*> groups;
566 GtkActionGroup* mainActions = 0;
567 if ( groups.find(desktop) != groups.end() ) {
568 mainActions = groups[desktop];
569 }
571 if ( !mainActions ) {
572 mainActions = gtk_action_group_new("main");
573 groups[desktop] = mainActions;
574 }
576 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
577 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
578 if ( verb ) {
579 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
580 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
581 gtk_action_group_add_action( mainActions, act );
582 }
583 }
584 }
586 return mainActions;
587 }
590 GtkWidget *
591 sp_tool_toolbox_new()
592 {
593 GtkTooltips *tt = gtk_tooltips_new();
594 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
596 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
597 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
599 gtk_widget_set_sensitive(tb, FALSE);
601 GtkWidget *hb = gtk_handle_box_new();
602 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
603 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
604 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
606 gtk_container_add(GTK_CONTAINER(hb), tb);
607 gtk_widget_show(GTK_WIDGET(tb));
609 sigc::connection* conn = new sigc::connection;
610 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
612 return hb;
613 }
615 static void
616 aux_toolbox_attached(GtkHandleBox */*toolbox*/, GtkWidget *child)
617 {
618 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
619 gtk_widget_queue_resize(child);
620 }
622 static void
623 aux_toolbox_detached(GtkHandleBox */*toolbox*/, GtkWidget *child)
624 {
625 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
626 gtk_widget_queue_resize(child);
627 }
629 GtkWidget *
630 sp_aux_toolbox_new()
631 {
632 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
634 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
635 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
636 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
637 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
638 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
640 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
641 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
643 gtk_widget_set_sensitive(tb, FALSE);
645 GtkWidget *hb = gtk_handle_box_new();
646 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
647 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
648 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
650 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
651 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
653 gtk_container_add(GTK_CONTAINER(hb), tb);
654 gtk_widget_show(GTK_WIDGET(tb));
656 sigc::connection* conn = new sigc::connection;
657 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
659 return hb;
660 }
662 //####################################
663 //# Commands Bar
664 //####################################
666 GtkWidget *
667 sp_commands_toolbox_new()
668 {
669 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
671 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
672 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
673 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
674 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
675 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
677 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
678 gtk_widget_set_sensitive(tb, FALSE);
680 GtkWidget *hb = gtk_handle_box_new();
681 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
682 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
683 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
685 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
686 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
688 gtk_container_add(GTK_CONTAINER(hb), tb);
689 gtk_widget_show(GTK_WIDGET(tb));
691 sigc::connection* conn = new sigc::connection;
692 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
694 return hb;
695 }
697 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
698 gchar const *label, gchar const *shortLabel, gchar const *tooltip,
699 gchar const *path, gchar const *data, gdouble def,
700 GtkWidget *focusTarget,
701 GtkWidget *us,
702 GObject *dataKludge,
703 gboolean altx, gchar const *altx_mark,
704 gdouble lower, gdouble upper, gdouble step, gdouble page,
705 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
706 void (*callback)(GtkAdjustment *, GObject *),
707 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
708 {
709 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
710 lower, upper, step, page, page ) );
711 if (us) {
712 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
713 }
715 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
717 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
718 if ( shortLabel ) {
719 g_object_set( act, "short_label", shortLabel, NULL );
720 }
722 if ( (descrCount > 0) && descrLabels && descrValues ) {
723 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
724 }
726 if ( focusTarget ) {
727 ege_adjustment_action_set_focuswidget( act, focusTarget );
728 }
730 if ( altx && altx_mark ) {
731 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
732 }
734 if ( dataKludge ) {
735 g_object_set_data( dataKludge, data, adj );
736 }
738 // Using a cast just to make sure we pass in the right kind of function pointer
739 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
741 return act;
742 }
745 //####################################
746 //# node editing callbacks
747 //####################################
749 /**
750 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
751 */
752 static ShapeEditor *get_current_shape_editor()
753 {
754 if (!SP_ACTIVE_DESKTOP) {
755 return NULL;
756 }
758 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
760 if (!SP_IS_NODE_CONTEXT(event_context)) {
761 return NULL;
762 }
764 return SP_NODE_CONTEXT(event_context)->shape_editor;
765 }
768 void
769 sp_node_path_edit_add(void)
770 {
771 ShapeEditor *shape_editor = get_current_shape_editor();
772 if (shape_editor) shape_editor->add_node();
773 }
775 void
776 sp_node_path_edit_delete(void)
777 {
778 ShapeEditor *shape_editor = get_current_shape_editor();
779 if (shape_editor) shape_editor->delete_nodes();
780 }
782 void
783 sp_node_path_edit_delete_segment(void)
784 {
785 ShapeEditor *shape_editor = get_current_shape_editor();
786 if (shape_editor) shape_editor->delete_segment();
787 }
789 void
790 sp_node_path_edit_break(void)
791 {
792 ShapeEditor *shape_editor = get_current_shape_editor();
793 if (shape_editor) shape_editor->break_at_nodes();
794 }
796 void
797 sp_node_path_edit_join(void)
798 {
799 ShapeEditor *shape_editor = get_current_shape_editor();
800 if (shape_editor) shape_editor->join_nodes();
801 }
803 void
804 sp_node_path_edit_join_segment(void)
805 {
806 ShapeEditor *shape_editor = get_current_shape_editor();
807 if (shape_editor) shape_editor->join_segments();
808 }
810 void
811 sp_node_path_edit_toline(void)
812 {
813 ShapeEditor *shape_editor = get_current_shape_editor();
814 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
815 }
817 void
818 sp_node_path_edit_tocurve(void)
819 {
820 ShapeEditor *shape_editor = get_current_shape_editor();
821 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
822 }
824 void
825 sp_node_path_edit_cusp(void)
826 {
827 ShapeEditor *shape_editor = get_current_shape_editor();
828 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
829 }
831 void
832 sp_node_path_edit_smooth(void)
833 {
834 ShapeEditor *shape_editor = get_current_shape_editor();
835 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
836 }
838 void
839 sp_node_path_edit_symmetrical(void)
840 {
841 ShapeEditor *shape_editor = get_current_shape_editor();
842 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
843 }
845 static void toggle_show_handles (GtkToggleAction *act, gpointer /*data*/) {
846 bool show = gtk_toggle_action_get_active( act );
847 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
848 ShapeEditor *shape_editor = get_current_shape_editor();
849 if (shape_editor) shape_editor->show_handles(show);
850 }
852 void sp_node_path_edit_nextLPEparam (GtkAction */*act*/, gpointer data) {
853 sp_selection_next_patheffect_param( reinterpret_cast<SPDesktop*>(data) );
854 }
856 /* is called when the node selection is modified */
857 static void
858 sp_node_toolbox_coord_changed(gpointer /*shape_editor*/, GObject *tbl)
859 {
860 GtkAction* xact = GTK_ACTION( g_object_get_data( tbl, "nodes_x_action" ) );
861 GtkAction* yact = GTK_ACTION( g_object_get_data( tbl, "nodes_y_action" ) );
862 GtkAdjustment *xadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(xact));
863 GtkAdjustment *yadj = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION(yact));
865 // quit if run by the attr_changed listener
866 if (g_object_get_data( tbl, "freeze" )) {
867 return;
868 }
870 // in turn, prevent listener from responding
871 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
873 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
874 SPUnit const *unit = tracker->getActiveUnit();
876 ShapeEditor *shape_editor = get_current_shape_editor();
877 if (shape_editor && shape_editor->has_nodepath()) {
878 Inkscape::NodePath::Path *nodepath = shape_editor->get_nodepath();
879 int n_selected = 0;
880 if (nodepath) {
881 n_selected = nodepath->numSelected();
882 }
884 if (n_selected == 0) {
885 gtk_action_set_sensitive(xact, FALSE);
886 gtk_action_set_sensitive(yact, FALSE);
887 } else {
888 gtk_action_set_sensitive(xact, TRUE);
889 gtk_action_set_sensitive(yact, TRUE);
890 NR::Coord oldx = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
891 NR::Coord oldy = sp_units_get_pixels(gtk_adjustment_get_value(xadj), *unit);
893 if (n_selected == 1) {
894 NR::Point sel_node = nodepath->singleSelectedCoords();
895 if (oldx != sel_node[NR::X] || oldy != sel_node[NR::Y]) {
896 gtk_adjustment_set_value(xadj, sp_pixels_get_units(sel_node[NR::X], *unit));
897 gtk_adjustment_set_value(yadj, sp_pixels_get_units(sel_node[NR::Y], *unit));
898 }
899 } else {
900 NR::Maybe<NR::Coord> x = sp_node_selected_common_coord(nodepath, NR::X);
901 NR::Maybe<NR::Coord> y = sp_node_selected_common_coord(nodepath, NR::Y);
902 if ((x && ((*x) != oldx)) || (y && ((*y) != oldy))) {
903 /* Note: Currently x and y will always have a value, even if the coordinates of the
904 selected nodes don't coincide (in this case we use the coordinates of the center
905 of the bounding box). So the entries are never set to zero. */
906 // FIXME: Maybe we should clear the entry if several nodes are selected
907 // instead of providing a kind of average value
908 gtk_adjustment_set_value(xadj, sp_pixels_get_units(x ? (*x) : 0.0, *unit));
909 gtk_adjustment_set_value(yadj, sp_pixels_get_units(y ? (*y) : 0.0, *unit));
910 }
911 }
912 }
913 } else {
914 // no shape-editor or nodepath yet (when we just switched to the tool); coord entries must be inactive
915 gtk_action_set_sensitive(xact, FALSE);
916 gtk_action_set_sensitive(yact, FALSE);
917 }
919 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
920 }
922 static void
923 sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
924 {
925 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
927 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
928 SPUnit const *unit = tracker->getActiveUnit();
930 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
931 prefs_set_double_attribute("tools.nodes", value_name, sp_units_get_pixels(adj->value, *unit));
932 }
934 // quit if run by the attr_changed listener
935 if (g_object_get_data( tbl, "freeze" )) {
936 return;
937 }
939 // in turn, prevent listener from responding
940 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
942 ShapeEditor *shape_editor = get_current_shape_editor();
943 if (shape_editor && shape_editor->has_nodepath()) {
944 double val = sp_units_get_pixels(gtk_adjustment_get_value(adj), *unit);
945 if (!strcmp(value_name, "x")) {
946 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::X);
947 }
948 if (!strcmp(value_name, "y")) {
949 sp_node_selected_move_absolute(shape_editor->get_nodepath(), val, NR::Y);
950 }
951 }
953 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
954 }
956 static void
957 sp_node_path_x_value_changed(GtkAdjustment *adj, GObject *tbl)
958 {
959 sp_node_path_value_changed(adj, tbl, "x");
960 }
962 static void
963 sp_node_path_y_value_changed(GtkAdjustment *adj, GObject *tbl)
964 {
965 sp_node_path_value_changed(adj, tbl, "y");
966 }
968 //################################
969 //## Node Editing Toolbox ##
970 //################################
972 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
973 {
974 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
975 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
976 g_object_set_data( holder, "tracker", tracker );
978 {
979 InkAction* inky = ink_action_new( "NodeInsertAction",
980 _("Insert node"),
981 _("Insert new nodes into selected segments"),
982 "node_insert",
983 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
984 g_object_set( inky, "short_label", _("Insert"), NULL );
985 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
986 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
987 }
989 {
990 InkAction* inky = ink_action_new( "NodeDeleteAction",
991 _("Delete node"),
992 _("Delete selected nodes"),
993 "node_delete",
994 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
995 g_object_set( inky, "short_label", _("Delete"), NULL );
996 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
997 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
998 }
1000 {
1001 InkAction* inky = ink_action_new( "NodeJoinAction",
1002 _("Join endnodes"),
1003 _("Join selected endnodes"),
1004 "node_join",
1005 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1006 g_object_set( inky, "short_label", _("Join"), NULL );
1007 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
1008 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1009 }
1011 {
1012 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
1013 _("Join Segment"),
1014 _("Join selected endnodes with a new segment"),
1015 "node_join_segment",
1016 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1017 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
1018 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1019 }
1021 {
1022 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
1023 _("Delete Segment"),
1024 _("Split path between two non-endpoint nodes"),
1025 "node_delete_segment",
1026 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1027 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
1028 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1029 }
1031 {
1032 InkAction* inky = ink_action_new( "NodeBreakAction",
1033 _("Node Break"),
1034 _("Break path at selected nodes"),
1035 "node_break",
1036 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1037 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
1038 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1039 }
1041 {
1042 InkAction* inky = ink_action_new( "NodeCuspAction",
1043 _("Node Cusp"),
1044 _("Make selected nodes corner"),
1045 "node_cusp",
1046 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1047 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
1048 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1049 }
1051 {
1052 InkAction* inky = ink_action_new( "NodeSmoothAction",
1053 _("Node Smooth"),
1054 _("Make selected nodes smooth"),
1055 "node_smooth",
1056 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1057 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
1058 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1059 }
1061 {
1062 InkAction* inky = ink_action_new( "NodeSymmetricAction",
1063 _("Node Symmetric"),
1064 _("Make selected nodes symmetric"),
1065 "node_symmetric",
1066 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1067 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
1068 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1069 }
1071 {
1072 InkAction* inky = ink_action_new( "NodeLineAction",
1073 _("Node Line"),
1074 _("Make selected segments lines"),
1075 "node_line",
1076 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1077 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
1078 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1079 }
1081 {
1082 InkAction* inky = ink_action_new( "NodeCurveAction",
1083 _("Node Curve"),
1084 _("Make selected segments curves"),
1085 "node_curve",
1086 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
1087 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
1088 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1089 }
1091 {
1092 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
1093 _("Show Handles"),
1094 _("Show the Bezier handles of selected nodes"),
1095 "nodes_show_handles",
1096 Inkscape::ICON_SIZE_DECORATION );
1097 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1098 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
1099 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
1100 }
1102 {
1103 InkAction* inky = ink_action_new( "EditNextLPEParameterAction",
1104 _("Next Path Effect Parameter"),
1105 _("Show next Path Effect parameter for editing"),
1106 "edit_next_parameter",
1107 Inkscape::ICON_SIZE_DECORATION );
1108 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_nextLPEparam), desktop );
1109 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
1110 }
1112 /* X coord of selected node(s) */
1113 {
1114 EgeAdjustmentAction* eact = 0;
1115 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1116 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1117 eact = create_adjustment_action( "NodeXAction",
1118 _("X coordinate:"), _("X:"), _("X coordinate of selected node(s)"),
1119 "tools.nodes", "Xcoord", 0,
1120 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-nodes",
1121 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1122 labels, values, G_N_ELEMENTS(labels),
1123 sp_node_path_x_value_changed );
1124 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1125 g_object_set_data( holder, "nodes_x_action", eact );
1126 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1127 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1128 }
1130 /* Y coord of selected node(s) */
1131 {
1132 EgeAdjustmentAction* eact = 0;
1133 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1134 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
1135 eact = create_adjustment_action( "NodeYAction",
1136 _("Y coordinate:"), _("Y:"), _("Y coordinate of selected node(s)"),
1137 "tools.nodes", "Ycoord", 0,
1138 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1139 -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1140 labels, values, G_N_ELEMENTS(labels),
1141 sp_node_path_y_value_changed );
1142 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1143 g_object_set_data( holder, "nodes_y_action", eact );
1144 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1145 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1146 }
1148 // add the units menu
1149 {
1150 GtkAction* act = tracker->createAction( "NodeUnitsAction", _("Units"), ("") );
1151 gtk_action_group_add_action( mainActions, act );
1152 }
1154 sigc::connection *connection = new sigc::connection (
1155 desktop->connectToolSubselectionChanged(sigc::bind (sigc::ptr_fun(sp_node_toolbox_coord_changed), (GObject *)holder))
1156 );
1158 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1159 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1160 } // end of sp_node_toolbox_prep()
1163 //########################
1164 //## Zoom Toolbox ##
1165 //########################
1167 static void sp_zoom_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
1168 {
1169 // no custom GtkAction setup needed
1170 } // end of sp_zoom_toolbox_prep()
1172 void
1173 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1174 {
1175 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_tool_toolbox, update_tool_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
1176 }
1179 void
1180 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1181 {
1182 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_aux_toolbox, update_aux_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
1183 }
1185 void
1186 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
1187 {
1188 toolbox_set_desktop(gtk_bin_get_child(GTK_BIN(toolbox)), desktop, setup_commands_toolbox, update_commands_toolbox, static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), "event_context_connection")));
1189 }
1191 static void
1192 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
1193 {
1194 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
1195 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
1197 if (old_desktop) {
1198 GList *children, *iter;
1200 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
1201 for ( iter = children ; iter ; iter = iter->next ) {
1202 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
1203 }
1204 g_list_free(children);
1205 }
1207 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
1209 if (desktop) {
1210 gtk_widget_set_sensitive(toolbox, TRUE);
1211 setup_func(toolbox, desktop);
1212 update_func(desktop, desktop->event_context, toolbox);
1213 *conn = desktop->connectEventContextChanged
1214 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
1215 } else {
1216 gtk_widget_set_sensitive(toolbox, FALSE);
1217 }
1219 } // end of toolbox_set_desktop()
1222 static void
1223 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1224 {
1225 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
1226 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
1227 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
1228 // "toolbox.tools" was not set. Fallback to older value
1229 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
1231 // Copy the setting forwards
1232 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
1233 }
1234 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1236 for (int i = 0 ; tools[i].type_name ; i++ ) {
1237 GtkWidget *button =
1238 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
1239 SP_BUTTON_TYPE_TOGGLE,
1240 Inkscape::Verb::get(tools[i].verb),
1241 Inkscape::Verb::get(tools[i].doubleclick_verb),
1242 desktop,
1243 tooltips );
1245 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1246 (gpointer)button );
1247 }
1248 }
1251 static void
1252 update_tool_toolbox( SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox )
1253 {
1254 gchar const *const tname = ( eventcontext
1255 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1256 : NULL );
1257 for (int i = 0 ; tools[i].type_name ; i++ ) {
1258 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1259 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1260 }
1261 }
1263 static void
1264 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1265 {
1266 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1267 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1268 GtkUIManager* mgr = gtk_ui_manager_new();
1269 GError* errVal = 0;
1270 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1271 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1273 std::map<std::string, GtkWidget*> dataHolders;
1275 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1276 if ( aux_toolboxes[i].prep_func ) {
1277 // converted to GtkActions and UIManager
1279 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1280 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1281 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1282 dataHolders[aux_toolboxes[i].type_name] = kludge;
1283 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1284 } else {
1286 GtkWidget *sub_toolbox = 0;
1287 if (aux_toolboxes[i].create_func == NULL)
1288 sub_toolbox = sp_empty_toolbox_new(desktop);
1289 else {
1290 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1291 }
1293 gtk_size_group_add_widget( grouper, sub_toolbox );
1295 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1296 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1298 }
1299 }
1301 // Second pass to create toolbars *after* all GtkActions are created
1302 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1303 if ( aux_toolboxes[i].prep_func ) {
1304 // converted to GtkActions and UIManager
1306 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1308 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1309 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1311 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1312 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1313 g_free( tmp );
1314 tmp = 0;
1316 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1317 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1318 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1319 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1320 }
1321 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1324 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1326 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1327 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1328 swatch->setDesktop( desktop );
1329 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1330 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1331 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1332 gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, 0 );
1333 }
1335 gtk_widget_show_all( holder );
1336 sp_set_font_size_smaller( holder );
1338 gtk_size_group_add_widget( grouper, holder );
1340 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1341 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1342 }
1343 }
1345 g_object_unref( G_OBJECT(grouper) );
1346 }
1348 static void
1349 update_aux_toolbox(SPDesktop */*desktop*/, SPEventContext *eventcontext, GtkWidget *toolbox)
1350 {
1351 gchar const *tname = ( eventcontext
1352 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1353 : NULL );
1354 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1355 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1356 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1357 gtk_widget_show_all(sub_toolbox);
1358 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1359 } else {
1360 gtk_widget_hide(sub_toolbox);
1361 }
1362 }
1363 }
1365 static void
1366 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1367 {
1368 gchar const * descr =
1369 "<ui>"
1370 " <toolbar name='CommandsToolbar'>"
1371 " <toolitem action='FileNew' />"
1372 " <toolitem action='FileOpen' />"
1373 " <toolitem action='FileSave' />"
1374 " <toolitem action='FilePrint' />"
1375 " <separator />"
1376 " <toolitem action='FileImport' />"
1377 " <toolitem action='FileExport' />"
1378 " <separator />"
1379 " <toolitem action='EditUndo' />"
1380 " <toolitem action='EditRedo' />"
1381 " <separator />"
1382 " <toolitem action='EditCopy' />"
1383 " <toolitem action='EditCut' />"
1384 " <toolitem action='EditPaste' />"
1385 " <separator />"
1386 " <toolitem action='ZoomSelection' />"
1387 " <toolitem action='ZoomDrawing' />"
1388 " <toolitem action='ZoomPage' />"
1389 " <separator />"
1390 " <toolitem action='EditDuplicate' />"
1391 " <toolitem action='EditClone' />"
1392 " <toolitem action='EditUnlinkClone' />"
1393 " <separator />"
1394 " <toolitem action='SelectionGroup' />"
1395 " <toolitem action='SelectionUnGroup' />"
1396 " <separator />"
1397 " <toolitem action='DialogFillStroke' />"
1398 " <toolitem action='DialogText' />"
1399 " <toolitem action='DialogXMLEditor' />"
1400 " <toolitem action='DialogAlignDistribute' />"
1401 " <separator />"
1402 " <toolitem action='DialogPreferences' />"
1403 " <toolitem action='DialogDocumentProperties' />"
1404 " </toolbar>"
1405 "</ui>";
1406 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1409 GtkUIManager* mgr = gtk_ui_manager_new();
1410 GError* errVal = 0;
1412 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1413 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1415 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1416 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1417 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1418 }
1419 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1420 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1421 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1424 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1425 }
1427 static void
1428 update_commands_toolbox(SPDesktop */*desktop*/, SPEventContext */*eventcontext*/, GtkWidget */*toolbox*/)
1429 {
1430 }
1432 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1433 {
1434 gtk_widget_show(toolbox_toplevel);
1435 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1437 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1438 if (!shown_toolbox) {
1439 return;
1440 }
1441 gtk_widget_show(toolbox);
1443 // need to show the spacer, or the padding will be off
1444 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1445 gtk_widget_show(spacer);
1447 gtk_widget_show_all(shown_toolbox);
1448 }
1450 void
1451 aux_toolbox_space(GtkWidget *tb, gint space)
1452 {
1453 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1454 }
1456 static GtkWidget *
1457 sp_empty_toolbox_new(SPDesktop *desktop)
1458 {
1459 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1460 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1461 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1463 gtk_widget_show_all(tbl);
1464 sp_set_font_size_smaller (tbl);
1466 return tbl;
1467 }
1469 // helper UI functions
1471 GtkWidget *
1472 sp_tb_spinbutton(
1473 gchar *label, gchar const *tooltip,
1474 gchar const *path, gchar const *data, gdouble def,
1475 GtkWidget *us,
1476 GtkWidget *tbl,
1477 gboolean altx, gchar const *altx_mark,
1478 gdouble lower, gdouble upper, gdouble step, gdouble page,
1479 void (*callback)(GtkAdjustment *, GtkWidget *),
1480 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1481 {
1482 GtkTooltips *tt = gtk_tooltips_new();
1484 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1486 GtkWidget *l = gtk_label_new(label);
1487 gtk_widget_show(l);
1488 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1489 gtk_container_add(GTK_CONTAINER(hb), l);
1491 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1492 lower, upper, step, page, page);
1493 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1494 if (us)
1495 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1497 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1498 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1499 if (altx)
1500 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1501 gtk_widget_set_size_request(sb,
1502 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1503 AUX_SPINBUTTON_HEIGHT);
1504 gtk_widget_show(sb);
1505 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1506 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1507 gtk_container_add(GTK_CONTAINER(hb), sb);
1508 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1510 return hb;
1511 }
1513 #define MODE_LABEL_WIDTH 70
1515 //########################
1516 //## Star ##
1517 //########################
1519 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1520 {
1521 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1523 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1524 // do not remember prefs if this call is initiated by an undo change, because undoing object
1525 // creation sets bogus values to its attributes before it is deleted
1526 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1527 }
1529 // quit if run by the attr_changed listener
1530 if (g_object_get_data( dataKludge, "freeze" )) {
1531 return;
1532 }
1534 // in turn, prevent listener from responding
1535 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1537 bool modmade = false;
1539 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1540 GSList const *items = selection->itemList();
1541 for (; items != NULL; items = items->next) {
1542 if (SP_IS_STAR((SPItem *) items->data)) {
1543 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1544 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1545 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1546 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1547 + M_PI / (gint)adj->value));
1548 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1549 modmade = true;
1550 }
1551 }
1552 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1553 _("Star: Change number of corners"));
1555 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1556 }
1558 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1559 {
1560 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1562 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1563 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1564 }
1566 // quit if run by the attr_changed listener
1567 if (g_object_get_data( dataKludge, "freeze" )) {
1568 return;
1569 }
1571 // in turn, prevent listener from responding
1572 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1574 bool modmade = false;
1575 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1576 GSList const *items = selection->itemList();
1577 for (; items != NULL; items = items->next) {
1578 if (SP_IS_STAR((SPItem *) items->data)) {
1579 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1581 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1582 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1583 if (r2 < r1) {
1584 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1585 } else {
1586 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1587 }
1589 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1590 modmade = true;
1591 }
1592 }
1594 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1595 _("Star: Change spoke ratio"));
1597 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1598 }
1600 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1601 {
1602 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1603 bool flat = ege_select_one_action_get_active( act ) == 0;
1605 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1606 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1607 flat ? "true" : "false" );
1608 }
1610 // quit if run by the attr_changed listener
1611 if (g_object_get_data( dataKludge, "freeze" )) {
1612 return;
1613 }
1615 // in turn, prevent listener from responding
1616 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1618 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1619 GSList const *items = selection->itemList();
1620 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1621 bool modmade = false;
1623 if ( prop_action ) {
1624 gtk_action_set_sensitive( prop_action, !flat );
1625 }
1627 for (; items != NULL; items = items->next) {
1628 if (SP_IS_STAR((SPItem *) items->data)) {
1629 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1630 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1631 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1632 modmade = true;
1633 }
1634 }
1636 if (modmade) {
1637 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1638 flat ? _("Make polygon") : _("Make star"));
1639 }
1641 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1642 }
1644 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1645 {
1646 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1648 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1649 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1650 }
1652 // quit if run by the attr_changed listener
1653 if (g_object_get_data( dataKludge, "freeze" )) {
1654 return;
1655 }
1657 // in turn, prevent listener from responding
1658 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1660 bool modmade = false;
1662 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1663 GSList const *items = selection->itemList();
1664 for (; items != NULL; items = items->next) {
1665 if (SP_IS_STAR((SPItem *) items->data)) {
1666 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1667 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1668 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1669 modmade = true;
1670 }
1671 }
1672 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1673 _("Star: Change rounding"));
1675 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1676 }
1678 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1679 {
1680 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1682 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1683 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1684 }
1686 // quit if run by the attr_changed listener
1687 if (g_object_get_data( dataKludge, "freeze" )) {
1688 return;
1689 }
1691 // in turn, prevent listener from responding
1692 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1694 bool modmade = false;
1696 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1697 GSList const *items = selection->itemList();
1698 for (; items != NULL; items = items->next) {
1699 if (SP_IS_STAR((SPItem *) items->data)) {
1700 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1701 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1702 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1703 modmade = true;
1704 }
1705 }
1706 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1707 _("Star: Change randomization"));
1709 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1710 }
1713 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1714 gchar const */*old_value*/, gchar const */*new_value*/,
1715 bool /*is_interactive*/, gpointer data)
1716 {
1717 GtkWidget *tbl = GTK_WIDGET(data);
1719 // quit if run by the _changed callbacks
1720 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1721 return;
1722 }
1724 // in turn, prevent callbacks from responding
1725 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1727 GtkAdjustment *adj = 0;
1729 if (!strcmp(name, "inkscape:randomized")) {
1730 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1731 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1732 } else if (!strcmp(name, "inkscape:rounded")) {
1733 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1734 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1735 } else if (!strcmp(name, "inkscape:flatsided")) {
1736 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1737 char const *flatsides = repr->attribute("inkscape:flatsided");
1738 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1739 if ( flatsides && !strcmp(flatsides,"false") ) {
1740 ege_select_one_action_set_active( flat_action, 1 );
1741 gtk_action_set_sensitive( prop_action, TRUE );
1742 } else {
1743 ege_select_one_action_set_active( flat_action, 0 );
1744 gtk_action_set_sensitive( prop_action, FALSE );
1745 }
1746 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1747 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1748 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1749 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1750 if (r2 < r1) {
1751 gtk_adjustment_set_value(adj, r2/r1);
1752 } else {
1753 gtk_adjustment_set_value(adj, r1/r2);
1754 }
1755 } else if (!strcmp(name, "sodipodi:sides")) {
1756 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1757 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1758 }
1760 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1761 }
1764 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1765 {
1766 NULL, /* child_added */
1767 NULL, /* child_removed */
1768 star_tb_event_attr_changed,
1769 NULL, /* content_changed */
1770 NULL /* order_changed */
1771 };
1774 /**
1775 * \param selection Should not be NULL.
1776 */
1777 static void
1778 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1779 {
1780 int n_selected = 0;
1781 Inkscape::XML::Node *repr = NULL;
1783 purge_repr_listener( tbl, tbl );
1785 for (GSList const *items = selection->itemList();
1786 items != NULL;
1787 items = items->next)
1788 {
1789 if (SP_IS_STAR((SPItem *) items->data)) {
1790 n_selected++;
1791 repr = SP_OBJECT_REPR((SPItem *) items->data);
1792 }
1793 }
1795 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1797 if (n_selected == 0) {
1798 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1799 } else if (n_selected == 1) {
1800 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1802 if (repr) {
1803 g_object_set_data( tbl, "repr", repr );
1804 Inkscape::GC::anchor(repr);
1805 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1806 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1807 }
1808 } else {
1809 // FIXME: implement averaging of all parameters for multiple selected stars
1810 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1811 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1812 }
1813 }
1816 static void sp_stb_defaults( GtkWidget */*widget*/, GObject *dataKludge )
1817 {
1818 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1819 // callbacks to lump all the changes for all selected objects in one undo step
1821 GtkAdjustment *adj = 0;
1823 // fixme: make settable in prefs!
1824 gint mag = 5;
1825 gdouble prop = 0.5;
1826 gboolean flat = FALSE;
1827 gdouble randomized = 0;
1828 gdouble rounded = 0;
1830 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1831 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1833 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1834 gtk_action_set_sensitive( sb2, !flat );
1836 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1837 gtk_adjustment_set_value(adj, mag);
1838 gtk_adjustment_value_changed(adj);
1840 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1841 gtk_adjustment_set_value(adj, prop);
1842 gtk_adjustment_value_changed(adj);
1844 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1845 gtk_adjustment_set_value(adj, rounded);
1846 gtk_adjustment_value_changed(adj);
1848 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1849 gtk_adjustment_set_value(adj, randomized);
1850 gtk_adjustment_value_changed(adj);
1851 }
1854 void
1855 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1856 {
1857 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1858 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1859 GtkWidget *l = gtk_label_new(NULL);
1860 gtk_label_set_markup(GTK_LABEL(l), title);
1861 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1862 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1863 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1864 }
1867 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1868 {
1869 {
1870 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1871 ege_output_action_set_use_markup( act, TRUE );
1872 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1873 g_object_set_data( holder, "mode_action", act );
1874 }
1876 {
1877 //EgeAdjustmentAction* calligraphy_angle = 0;
1878 EgeAdjustmentAction* eact = 0;
1879 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1880 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1882 /* Flatsided checkbox */
1883 {
1884 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1886 GtkTreeIter iter;
1887 gtk_list_store_append( model, &iter );
1888 gtk_list_store_set( model, &iter,
1889 0, _("Polygon"),
1890 1, _("Regular polygon (with one handle) instead of a star"),
1891 2, "star_flat",
1892 -1 );
1894 gtk_list_store_append( model, &iter );
1895 gtk_list_store_set( model, &iter,
1896 0, _("Star"),
1897 1, _("Star instead of a regular polygon (with one handle)"),
1898 2, "star_angled",
1899 -1 );
1901 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
1902 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1903 g_object_set_data( holder, "flat_action", act );
1905 ege_select_one_action_set_appearance( act, "full" );
1906 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1907 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1908 ege_select_one_action_set_icon_column( act, 2 );
1909 ege_select_one_action_set_tooltip_column( act, 1 );
1911 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1912 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1913 }
1915 /* Magnitude */
1916 {
1917 gchar const* labels[] = {_("triangle/tri-star"), _("square/quad-star"), _("pentagon/five-pointed star"), _("hexagon/six-pointed star"), 0, 0, 0, 0, 0};
1918 gdouble values[] = {3, 4, 5, 6, 7, 8, 10, 12, 20};
1919 eact = create_adjustment_action( "MagnitudeAction",
1920 _("Corners"), _("Corners:"), _("Number of corners of a polygon or star"),
1921 "tools.shapes.star", "magnitude", 3,
1922 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1923 3, 1024, 1, 5,
1924 labels, values, G_N_ELEMENTS(labels),
1925 sp_stb_magnitude_value_changed,
1926 1.0, 0 );
1927 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1928 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1929 }
1931 /* Spoke ratio */
1932 {
1933 gchar const* labels[] = {_("thin-ray star"), 0, _("pentagram"), _("hexagram"), _("heptagram"), _("octagram"), _("regular polygon")};
1934 gdouble values[] = {0.01, 0.2, 0.382, 0.577, 0.692, 0.765, 1};
1935 eact = create_adjustment_action( "SpokeAction",
1936 _("Spoke ratio"), _("Spoke ratio:"),
1937 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1938 // Base radius is the same for the closest handle.
1939 _("Base radius to tip radius ratio"),
1940 "tools.shapes.star", "proportion", 0.5,
1941 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1942 0.01, 1.0, 0.01, 0.1,
1943 labels, values, G_N_ELEMENTS(labels),
1944 sp_stb_proportion_value_changed );
1945 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1946 g_object_set_data( holder, "prop_action", eact );
1947 }
1949 if ( !isFlatSided ) {
1950 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1951 } else {
1952 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1953 }
1955 /* Roundedness */
1956 {
1957 gchar const* labels[] = {_("stretched"), _("twisted"), _("slightly pinched"), _("NOT rounded"), _("slightly rounded"), _("visibly rounded"), _("well rounded"), _("amply rounded"), 0, _("stretched"), _("blown up")};
1958 gdouble values[] = {-1, -0.2, -0.03, 0, 0.05, 0.1, 0.2, 0.3, 0.5, 1, 10};
1959 eact = create_adjustment_action( "RoundednessAction",
1960 _("Rounded"), _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1961 "tools.shapes.star", "rounded", 0.0,
1962 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1963 -10.0, 10.0, 0.01, 0.1,
1964 labels, values, G_N_ELEMENTS(labels),
1965 sp_stb_rounded_value_changed );
1966 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1967 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1968 }
1970 /* Randomization */
1971 {
1972 gchar const* labels[] = {_("NOT randomized"), _("slightly irregular"), _("visibly randomized"), _("strongly randomized"), _("blown up")};
1973 gdouble values[] = {0, 0.01, 0.1, 0.5, 10};
1974 eact = create_adjustment_action( "RandomizationAction",
1975 _("Randomized"), _("Randomized:"), _("Scatter randomly the corners and angles"),
1976 "tools.shapes.star", "randomized", 0.0,
1977 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1978 -10.0, 10.0, 0.001, 0.01,
1979 labels, values, G_N_ELEMENTS(labels),
1980 sp_stb_randomized_value_changed, 0.1, 3 );
1981 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1982 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1983 }
1984 }
1986 {
1987 /* Reset */
1988 {
1989 GtkAction* act = gtk_action_new( "StarResetAction",
1990 _("Defaults"),
1991 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1992 GTK_STOCK_CLEAR );
1993 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1994 gtk_action_group_add_action( mainActions, act );
1995 gtk_action_set_sensitive( act, TRUE );
1996 }
1997 }
1999 sigc::connection *connection = new sigc::connection(
2000 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
2001 );
2002 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2003 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2004 }
2007 //########################
2008 //## Rect ##
2009 //########################
2011 static void sp_rtb_sensitivize( GObject *tbl )
2012 {
2013 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
2014 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
2015 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
2017 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
2018 gtk_action_set_sensitive( not_rounded, FALSE );
2019 } else {
2020 gtk_action_set_sensitive( not_rounded, TRUE );
2021 }
2022 }
2025 static void
2026 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
2027 void (*setter)(SPRect *, gdouble))
2028 {
2029 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2031 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
2032 SPUnit const *unit = tracker->getActiveUnit();
2034 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2035 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
2036 }
2038 // quit if run by the attr_changed listener
2039 if (g_object_get_data( tbl, "freeze" )) {
2040 return;
2041 }
2043 // in turn, prevent listener from responding
2044 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
2046 bool modmade = false;
2047 Inkscape::Selection *selection = sp_desktop_selection(desktop);
2048 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
2049 if (SP_IS_RECT(items->data)) {
2050 if (adj->value != 0) {
2051 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
2052 } else {
2053 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
2054 }
2055 modmade = true;
2056 }
2057 }
2059 sp_rtb_sensitivize( tbl );
2061 if (modmade) {
2062 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
2063 _("Change rectangle"));
2064 }
2066 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2067 }
2069 static void
2070 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
2071 {
2072 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
2073 }
2075 static void
2076 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
2077 {
2078 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
2079 }
2081 static void
2082 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
2083 {
2084 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
2085 }
2087 static void
2088 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
2089 {
2090 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
2091 }
2095 static void
2096 sp_rtb_defaults( GtkWidget */*widget*/, GObject *obj)
2097 {
2098 GtkAdjustment *adj = 0;
2100 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
2101 gtk_adjustment_set_value(adj, 0.0);
2102 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
2103 gtk_adjustment_value_changed(adj);
2105 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
2106 gtk_adjustment_set_value(adj, 0.0);
2107 gtk_adjustment_value_changed(adj);
2109 sp_rtb_sensitivize( obj );
2110 }
2112 static void rect_tb_event_attr_changed(Inkscape::XML::Node */*repr*/, gchar const */*name*/,
2113 gchar const */*old_value*/, gchar const */*new_value*/,
2114 bool /*is_interactive*/, gpointer data)
2115 {
2116 GObject *tbl = G_OBJECT(data);
2118 // quit if run by the _changed callbacks
2119 if (g_object_get_data( tbl, "freeze" )) {
2120 return;
2121 }
2123 // in turn, prevent callbacks from responding
2124 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2126 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
2127 SPUnit const *unit = tracker->getActiveUnit();
2129 gpointer item = g_object_get_data( tbl, "item" );
2130 if (item && SP_IS_RECT(item)) {
2131 {
2132 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
2133 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
2134 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
2135 }
2137 {
2138 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
2139 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
2140 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
2141 }
2143 {
2144 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
2145 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
2146 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
2147 }
2149 {
2150 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
2151 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
2152 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
2153 }
2154 }
2156 sp_rtb_sensitivize( tbl );
2158 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2159 }
2162 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
2163 NULL, /* child_added */
2164 NULL, /* child_removed */
2165 rect_tb_event_attr_changed,
2166 NULL, /* content_changed */
2167 NULL /* order_changed */
2168 };
2170 /**
2171 * \param selection should not be NULL.
2172 */
2173 static void
2174 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2175 {
2176 int n_selected = 0;
2177 Inkscape::XML::Node *repr = NULL;
2178 SPItem *item = NULL;
2180 if ( g_object_get_data( tbl, "repr" ) ) {
2181 g_object_set_data( tbl, "item", NULL );
2182 }
2183 purge_repr_listener( tbl, tbl );
2185 for (GSList const *items = selection->itemList();
2186 items != NULL;
2187 items = items->next) {
2188 if (SP_IS_RECT((SPItem *) items->data)) {
2189 n_selected++;
2190 item = (SPItem *) items->data;
2191 repr = SP_OBJECT_REPR(item);
2192 }
2193 }
2195 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2197 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2199 if (n_selected == 0) {
2200 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2202 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2203 gtk_action_set_sensitive(w, FALSE);
2204 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2205 gtk_action_set_sensitive(h, FALSE);
2207 } else if (n_selected == 1) {
2208 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2209 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2211 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2212 gtk_action_set_sensitive(w, TRUE);
2213 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2214 gtk_action_set_sensitive(h, TRUE);
2216 if (repr) {
2217 g_object_set_data( tbl, "repr", repr );
2218 g_object_set_data( tbl, "item", item );
2219 Inkscape::GC::anchor(repr);
2220 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2221 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2222 }
2223 } else {
2224 // FIXME: implement averaging of all parameters for multiple selected
2225 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2226 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2227 sp_rtb_sensitivize( tbl );
2228 }
2229 }
2232 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2233 {
2234 EgeAdjustmentAction* eact = 0;
2236 {
2237 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2238 ege_output_action_set_use_markup( act, TRUE );
2239 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2240 g_object_set_data( holder, "mode_action", act );
2241 }
2243 // rx/ry units menu: create
2244 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2245 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2246 // fixme: add % meaning per cent of the width/height
2247 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2248 g_object_set_data( holder, "tracker", tracker );
2250 /* W */
2251 {
2252 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2253 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2254 eact = create_adjustment_action( "RectWidthAction",
2255 _("Width"), _("W:"), _("Width of rectangle"),
2256 "tools.shapes.rect", "width", 0,
2257 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2258 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2259 labels, values, G_N_ELEMENTS(labels),
2260 sp_rtb_width_value_changed );
2261 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2262 g_object_set_data( holder, "width_action", eact );
2263 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2264 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2265 }
2267 /* H */
2268 {
2269 gchar const* labels[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2270 gdouble values[] = {1, 2, 3, 5, 10, 20, 50, 100, 200, 500};
2271 eact = create_adjustment_action( "RectHeightAction",
2272 _("Height"), _("H:"), _("Height of rectangle"),
2273 "tools.shapes.rect", "height", 0,
2274 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2275 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2276 labels, values, G_N_ELEMENTS(labels),
2277 sp_rtb_height_value_changed );
2278 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2279 g_object_set_data( holder, "height_action", eact );
2280 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2281 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2282 }
2284 /* rx */
2285 {
2286 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2287 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2288 eact = create_adjustment_action( "RadiusXAction",
2289 _("Horizontal radius"), _("Rx:"), _("Horizontal radius of rounded corners"),
2290 "tools.shapes.rect", "rx", 0,
2291 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2292 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2293 labels, values, G_N_ELEMENTS(labels),
2294 sp_rtb_rx_value_changed);
2295 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2296 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2297 }
2299 /* ry */
2300 {
2301 gchar const* labels[] = {_("not rounded"), 0, 0, 0, 0, 0, 0, 0, 0};
2302 gdouble values[] = {0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2303 eact = create_adjustment_action( "RadiusYAction",
2304 _("Vertical radius"), _("Ry:"), _("Vertical radius of rounded corners"),
2305 "tools.shapes.rect", "ry", 0,
2306 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2307 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2308 labels, values, G_N_ELEMENTS(labels),
2309 sp_rtb_ry_value_changed);
2310 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2311 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2312 }
2314 // add the units menu
2315 {
2316 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), ("") );
2317 gtk_action_group_add_action( mainActions, act );
2318 }
2320 /* Reset */
2321 {
2322 InkAction* inky = ink_action_new( "RectResetAction",
2323 _("Not rounded"),
2324 _("Make corners sharp"),
2325 "squared_corner",
2326 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2327 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2328 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2329 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2330 g_object_set_data( holder, "not_rounded", inky );
2331 }
2333 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2334 sp_rtb_sensitivize( holder );
2336 sigc::connection *connection = new sigc::connection(
2337 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2338 );
2339 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2340 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2341 }
2343 //########################
2344 //## 3D Box ##
2345 //########################
2347 static void box3d_toggle_vp_changed (GtkToggleAction *act, GObject *dataKludge, Proj::Axis axis)
2348 {
2349 SPDesktop *desktop = (SPDesktop *) g_object_get_data (dataKludge, "desktop");
2350 SPDocument *document = sp_desktop_document (desktop);
2351 // FIXME: Make sure document->current_persp3d is set correctly!
2352 Persp3D *persp = document->current_persp3d;
2354 g_return_if_fail (persp);
2356 // quit if run by the attr_changed listener
2357 if (g_object_get_data(dataKludge, "freeze")) {
2358 return;
2359 }
2361 // in turn, prevent listener from responding
2362 g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE));
2364 persp3d_set_VP_state(persp, axis, (gtk_toggle_action_get_active(act) ? Proj::VP_INFINITE : Proj::VP_FINITE));
2366 // FIXME: Can we merge this functionality with the one in box3d_persp_tb_event_attr_changed()?
2367 gchar *str;
2368 switch (axis) {
2369 case Proj::X:
2370 str = g_strdup ("box3d_angle_x_action");
2371 break;
2372 case Proj::Y:
2373 str = g_strdup ("box3d_angle_y_action");
2374 break;
2375 case Proj::Z:
2376 str = g_strdup ("box3d_angle_z_action");
2377 break;
2378 default:
2379 return;
2380 }
2381 GtkAction* angle_action = GTK_ACTION (g_object_get_data (dataKludge, str));
2382 if (angle_action) {
2383 gtk_action_set_sensitive (angle_action, !persp3d_VP_is_finite(persp, axis));
2384 }
2386 sp_document_maybe_done(sp_desktop_document(desktop), "toggle_vp", SP_VERB_CONTEXT_3DBOX,
2387 _("3D Box: Toggle VP"));
2388 //sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,_("3D Box: Toggle VP"));
2390 g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(FALSE));
2391 }
2393 static void box3d_toggle_vp_x_changed(GtkToggleAction *act, GObject *dataKludge)
2394 {
2395 box3d_toggle_vp_changed (act, dataKludge, Proj::X);
2396 }
2398 static void box3d_toggle_vp_y_changed(GtkToggleAction *act, GObject *dataKludge)
2399 {
2400 box3d_toggle_vp_changed (act, dataKludge, Proj::Y);
2401 }
2403 static void box3d_toggle_vp_z_changed(GtkToggleAction *act, GObject *dataKludge)
2404 {
2405 box3d_toggle_vp_changed (act, dataKludge, Proj::Z);
2406 }
2408 static void box3d_vp_angle_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis )
2409 {
2410 SPDesktop *desktop = (SPDesktop *) g_object_get_data(dataKludge, "desktop");
2411 Persp3D *persp = sp_desktop_document (desktop)->current_persp3d;
2413 // quit if run by the attr_changed listener
2414 if (g_object_get_data(dataKludge, "freeze")) {
2415 return;
2416 }
2418 // in turn, prevent listener from responding
2419 g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE));
2421 if (persp) {
2422 double angle = adj->value;
2423 // FIXME: Shouldn't we set the angle via the SVG attributes of the perspective instead of directly?
2424 if (persp3d_VP_is_finite(persp, axis)) {
2425 return;
2426 }
2427 persp->tmat.set_infinite_direction (axis, angle);
2428 persp3d_update_box_reprs (persp);
2430 sp_document_maybe_done(sp_desktop_document(desktop), "perspectiveangle", SP_VERB_CONTEXT_3DBOX,
2431 _("3D Box: Change perspective"));
2432 }
2434 g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(FALSE));
2435 }
2437 static void box3d_vpx_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2438 {
2439 box3d_vp_angle_changed (adj, dataKludge, Proj::X);
2440 }
2442 static void box3d_vpy_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2443 {
2444 box3d_vp_angle_changed (adj, dataKludge, Proj::Y);
2445 }
2447 static void box3d_vpz_angle_changed(GtkAdjustment *adj, GObject *dataKludge )
2448 {
2449 box3d_vp_angle_changed (adj, dataKludge, Proj::Z);
2450 }
2452 // normalize angle so that it lies in the interval [0,360]
2453 static double box3d_normalize_angle (double a) {
2454 double angle = a + ((int) (a/360.0))*360;
2455 if (angle < 0) {
2456 angle += 360.0;
2457 }
2458 return angle;
2459 }
2461 static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2462 gchar const *old_value, gchar const *new_value,
2463 bool is_interactive, gpointer data)
2464 {
2465 GtkWidget *tbl = GTK_WIDGET(data);
2467 // FIXME: if we check for "freeze" as in other tools, no action is performed at all ...
2468 // quit if run by the _changed callbacks
2469 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2470 //return;
2471 }
2473 // in turn, prevent callbacks from responding
2474 //g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2476 GtkAdjustment *adj = 0;
2477 double angle;
2478 SPDesktop *desktop = (SPDesktop *) g_object_get_data(G_OBJECT(tbl), "desktop");
2479 // FIXME: Get the persp from the box (should be the same, but ...)
2480 Persp3D *persp = sp_desktop_document (desktop)->current_persp3d;
2481 if (!strcmp(name, "inkscape:vp_x")) {
2482 GtkAction* act = GTK_ACTION (gtk_object_get_data (GTK_OBJECT(tbl), "box3d_angle_x_action"));
2483 GtkToggleAction* tact = GTK_TOGGLE_ACTION (gtk_object_get_data (GTK_OBJECT(tbl), "toggle_vp_x_action"));
2484 if (!persp3d_VP_is_finite(persp, Proj::X)) {
2485 gtk_action_set_sensitive(GTK_ACTION(act), TRUE);
2486 gtk_toggle_action_set_active(tact, TRUE);
2487 } else {
2488 gtk_action_set_sensitive(GTK_ACTION(act), FALSE);
2489 gtk_toggle_action_set_active(tact, FALSE);
2490 }
2492 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_x"));
2493 angle = persp3d_get_infinite_angle(persp, Proj::X);
2494 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
2495 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
2496 }
2497 }
2499 if (!strcmp(name, "inkscape:vp_y")) {
2500 GtkAction* act = GTK_ACTION (gtk_object_get_data (GTK_OBJECT(tbl), "box3d_angle_y_action"));
2501 GtkToggleAction* tact = GTK_TOGGLE_ACTION (gtk_object_get_data (GTK_OBJECT(tbl), "toggle_vp_y_action"));
2502 if (!persp3d_VP_is_finite(persp, Proj::Y)) {
2503 gtk_action_set_sensitive(GTK_ACTION(act), TRUE);
2504 gtk_toggle_action_set_active(tact, TRUE);
2505 } else {
2506 gtk_action_set_sensitive(GTK_ACTION(act), FALSE);
2507 gtk_toggle_action_set_active(tact, FALSE);
2508 }
2510 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_y"));
2511 angle = persp3d_get_infinite_angle(persp, Proj::Y);
2512 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
2513 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
2514 }
2515 }
2517 if (!strcmp(name, "inkscape:vp_z")) {
2518 GtkAction* act = GTK_ACTION (gtk_object_get_data (GTK_OBJECT(tbl), "box3d_angle_z_action"));
2519 GtkToggleAction* tact = GTK_TOGGLE_ACTION (gtk_object_get_data (GTK_OBJECT(tbl), "toggle_vp_z_action"));
2520 if (!persp3d_VP_is_finite(persp, Proj::Z)) {
2521 gtk_action_set_sensitive(GTK_ACTION(act), TRUE);
2522 gtk_toggle_action_set_active(tact, TRUE);
2523 } else {
2524 gtk_action_set_sensitive(GTK_ACTION(act), FALSE);
2525 gtk_toggle_action_set_active(tact, FALSE);
2526 }
2528 adj = GTK_ADJUSTMENT(gtk_object_get_data(GTK_OBJECT(tbl), "dir_vp_z"));
2529 angle = persp3d_get_infinite_angle(persp, Proj::Z);
2530 if (angle != NR_HUGE) { // FIXME: We should catch this error earlier (don't show the spinbutton at all)
2531 gtk_adjustment_set_value(adj, box3d_normalize_angle(angle));
2532 }
2533 }
2535 //g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2536 }
2538 static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events =
2539 {
2540 NULL, /* child_added */
2541 NULL, /* child_removed */
2542 box3d_persp_tb_event_attr_changed,
2543 NULL, /* content_changed */
2544 NULL /* order_changed */
2545 };
2547 /**
2548 * \param selection Should not be NULL.
2549 */
2550 // FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each
2551 // Change of the perspective, and not of the current selection (but how to refer to the toolbar then?)
2552 static void
2553 box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2554 {
2555 Inkscape::XML::Node *repr = NULL;
2556 purge_repr_listener(tbl, tbl);
2558 SPItem *item = selection->singleItem();
2559 if (item && SP_IS_BOX3D(item)) {
2560 //repr = SP_OBJECT_REPR(item);
2561 repr = SP_OBJECT_REPR(SP_BOX3D(item)->persp_ref->getObject());
2562 if (repr) {
2563 g_object_set_data(tbl, "repr", repr);
2564 Inkscape::GC::anchor(repr);
2565 sp_repr_add_listener(repr, &box3d_persp_tb_repr_events, tbl);
2566 sp_repr_synthesize_events(repr, &box3d_persp_tb_repr_events, tbl);
2567 }
2568 }
2569 }
2571 static void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2572 {
2573 EgeAdjustmentAction* eact = 0;
2574 SPDocument *document = sp_desktop_document (desktop);
2575 Persp3D *persp = document->current_persp3d;
2576 bool toggled = false;
2578 /* angle of VP in X direction */
2579 eact = create_adjustment_action("3DBoxPosAngleXAction",
2580 _("Angle X"), _("Angle X:"), _("Angle of infinite vanishing point in X direction"),
2581 "tools.shapes.3dbox", "dir_vp_x", persp3d_get_infinite_angle(persp, Proj::X),
2582 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-box3d",
2583 -360.0, 360.0, 1.0, 10.0,
2584 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2585 box3d_vpx_angle_changed,
2586 0.1, 1);
2587 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2588 g_object_set_data(holder, "box3d_angle_x_action", eact);
2589 if (!persp3d_VP_is_finite(persp, Proj::X)) {
2590 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2591 } else {
2592 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2593 }
2595 /* toggle VP in X direction */
2596 {
2597 InkToggleAction* act = ink_toggle_action_new("3DBoxVPXAction",
2598 _("Toggle VP in X direction"),
2599 _("Toggle VP in X direction between 'finite' and 'infinite' (= parallel)"),
2600 "toggle_vp_x",
2601 Inkscape::ICON_SIZE_DECORATION);
2602 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2603 g_object_set_data(holder, "toggle_vp_x_action", act);
2604 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), !persp3d_VP_is_finite(persp, Proj::X));
2605 /* we connect the signal after setting the state to avoid switching the state again */
2606 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(box3d_toggle_vp_x_changed), holder);
2607 }
2609 /* angle of VP in Y direction */
2610 eact = create_adjustment_action("3DBoxPosAngleYAction",
2611 _("Angle Y"), _("Angle Y:"), _("Angle of infinite vanishing point in Y direction"),
2612 "tools.shapes.3dbox", "dir_vp_y", persp3d_get_infinite_angle(persp, Proj::Y),
2613 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2614 -360.0, 360.0, 1.0, 10.0,
2615 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2616 box3d_vpy_angle_changed,
2617 0.1, 1);
2618 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2619 g_object_set_data(holder, "box3d_angle_y_action", eact);
2620 if (!persp3d_VP_is_finite(persp, Proj::Y)) {
2621 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2622 } else {
2623 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2624 }
2626 /* toggle VP in Y direction */
2627 {
2628 InkToggleAction* act = ink_toggle_action_new("3DBoxVPYAction",
2629 _("Toggle VP in Y direction"),
2630 _("Toggle VP in Y direction between 'finite' and 'infinite' (= parallel)"),
2631 "toggle_vp_y",
2632 Inkscape::ICON_SIZE_DECORATION);
2633 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2634 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), !persp3d_VP_is_finite(persp, Proj::Y));
2635 g_object_set_data(holder, "toggle_vp_y_action", act);
2636 /* we connect the signal after setting the state to avoid switching the state again */
2637 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(box3d_toggle_vp_y_changed), holder);
2638 }
2640 /* angle of VP in Z direction */
2641 eact = create_adjustment_action("3DBoxPosAngleZAction",
2642 _("Angle Z"), _("Angle Z:"), _("Angle of infinite vanishing point in Z direction"),
2643 "tools.shapes.3dbox", "dir_vp_z", persp3d_get_infinite_angle(persp, Proj::Z),
2644 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2645 -360.0, 360.0, 1.0, 10.0,
2646 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
2647 box3d_vpz_angle_changed,
2648 0.1, 1);
2650 gtk_action_group_add_action(mainActions, GTK_ACTION(eact));
2651 g_object_set_data(holder, "box3d_angle_z_action", eact);
2652 if (!persp3d_VP_is_finite(persp, Proj::Z)) {
2653 gtk_action_set_sensitive(GTK_ACTION(eact), TRUE);
2654 } else {
2655 gtk_action_set_sensitive(GTK_ACTION(eact), FALSE);
2656 }
2658 /* toggle VP in Z direction */
2659 {
2660 InkToggleAction* act = ink_toggle_action_new("3DBoxVPZAction",
2661 _("Toggle VP in Z direction"),
2662 _("Toggle VP in Z direction between 'finite' and 'infinite' (= parallel)"),
2663 "toggle_vp_z",
2664 Inkscape::ICON_SIZE_DECORATION);
2665 gtk_action_group_add_action(mainActions, GTK_ACTION(act));
2667 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(act), !persp3d_VP_is_finite(persp, Proj::Z));
2668 g_object_set_data(holder, "toggle_vp_z_action", act);
2669 /* we connect the signal after setting the state to avoid switching the state again */
2670 g_signal_connect_after(G_OBJECT(act), "toggled", G_CALLBACK(box3d_toggle_vp_z_changed), holder);
2671 }
2673 sigc::connection *connection = new sigc::connection(
2674 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), (GObject *)holder))
2675 );
2676 g_signal_connect(holder, "destroy", G_CALLBACK(delete_connection), connection);
2677 g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder);
2678 }
2680 //########################
2681 //## Spiral ##
2682 //########################
2684 static void
2685 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2686 {
2687 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2689 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2690 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2691 }
2693 // quit if run by the attr_changed listener
2694 if (g_object_get_data( tbl, "freeze" )) {
2695 return;
2696 }
2698 // in turn, prevent listener from responding
2699 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2701 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2703 bool modmade = false;
2704 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2705 items != NULL;
2706 items = items->next)
2707 {
2708 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2709 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2710 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2711 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2712 modmade = true;
2713 }
2714 }
2716 g_free(namespaced_name);
2718 if (modmade) {
2719 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2720 _("Change spiral"));
2721 }
2723 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2724 }
2726 static void
2727 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2728 {
2729 sp_spl_tb_value_changed(adj, tbl, "revolution");
2730 }
2732 static void
2733 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2734 {
2735 sp_spl_tb_value_changed(adj, tbl, "expansion");
2736 }
2738 static void
2739 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2740 {
2741 sp_spl_tb_value_changed(adj, tbl, "t0");
2742 }
2744 static void
2745 sp_spl_tb_defaults(GtkWidget */*widget*/, GtkObject *obj)
2746 {
2747 GtkWidget *tbl = GTK_WIDGET(obj);
2749 GtkAdjustment *adj;
2751 // fixme: make settable
2752 gdouble rev = 5;
2753 gdouble exp = 1.0;
2754 gdouble t0 = 0.0;
2756 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2757 gtk_adjustment_set_value(adj, rev);
2758 gtk_adjustment_value_changed(adj);
2760 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2761 gtk_adjustment_set_value(adj, exp);
2762 gtk_adjustment_value_changed(adj);
2764 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2765 gtk_adjustment_set_value(adj, t0);
2766 gtk_adjustment_value_changed(adj);
2768 spinbutton_defocus(GTK_OBJECT(tbl));
2769 }
2772 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
2773 gchar const */*old_value*/, gchar const */*new_value*/,
2774 bool /*is_interactive*/, gpointer data)
2775 {
2776 GtkWidget *tbl = GTK_WIDGET(data);
2778 // quit if run by the _changed callbacks
2779 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2780 return;
2781 }
2783 // in turn, prevent callbacks from responding
2784 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2786 GtkAdjustment *adj;
2787 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2788 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2790 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2791 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2793 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2794 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2796 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2797 }
2800 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2801 NULL, /* child_added */
2802 NULL, /* child_removed */
2803 spiral_tb_event_attr_changed,
2804 NULL, /* content_changed */
2805 NULL /* order_changed */
2806 };
2808 static void
2809 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2810 {
2811 int n_selected = 0;
2812 Inkscape::XML::Node *repr = NULL;
2814 purge_repr_listener( tbl, tbl );
2816 for (GSList const *items = selection->itemList();
2817 items != NULL;
2818 items = items->next)
2819 {
2820 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2821 n_selected++;
2822 repr = SP_OBJECT_REPR((SPItem *) items->data);
2823 }
2824 }
2826 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2828 if (n_selected == 0) {
2829 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2830 } else if (n_selected == 1) {
2831 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2833 if (repr) {
2834 g_object_set_data( tbl, "repr", repr );
2835 Inkscape::GC::anchor(repr);
2836 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2837 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2838 }
2839 } else {
2840 // FIXME: implement averaging of all parameters for multiple selected
2841 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2842 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2843 }
2844 }
2847 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2848 {
2849 EgeAdjustmentAction* eact = 0;
2851 {
2852 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2853 ege_output_action_set_use_markup( act, TRUE );
2854 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2855 g_object_set_data( holder, "mode_action", act );
2856 }
2858 /* Revolution */
2859 {
2860 gchar const* labels[] = {_("just a curve"), 0, _("one full revolution"), 0, 0, 0, 0, 0, 0};
2861 gdouble values[] = {0.01, 0.5, 1, 2, 3, 5, 10, 20, 50, 100};
2862 eact = create_adjustment_action( "SpiralRevolutionAction",
2863 _("Number of turns"), _("Turns:"), _("Number of revolutions"),
2864 "tools.shapes.spiral", "revolution", 3.0,
2865 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2866 0.01, 1024.0, 0.1, 1.0,
2867 labels, values, G_N_ELEMENTS(labels),
2868 sp_spl_tb_revolution_value_changed, 1, 2);
2869 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2870 }
2872 /* Expansion */
2873 {
2874 gchar const* labels[] = {_("circle"), _("edge is much denser"), _("edge is denser"), _("even"), _("center is denser"), _("center is much denser"), 0};
2875 gdouble values[] = {0, 0.1, 0.5, 1, 1.5, 5, 20};
2876 eact = create_adjustment_action( "SpiralExpansionAction",
2877 _("Divergence"), _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2878 "tools.shapes.spiral", "expansion", 1.0,
2879 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2880 0.0, 1000.0, 0.01, 1.0,
2881 labels, values, G_N_ELEMENTS(labels),
2882 sp_spl_tb_expansion_value_changed);
2883 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2884 }
2886 /* T0 */
2887 {
2888 gchar const* labels[] = {_("starts from center"), _("starts mid-way"), _("starts near edge")};
2889 gdouble values[] = {0, 0.5, 0.9};
2890 eact = create_adjustment_action( "SpiralT0Action",
2891 _("Inner radius"), _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2892 "tools.shapes.spiral", "t0", 0.0,
2893 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2894 0.0, 0.999, 0.01, 1.0,
2895 labels, values, G_N_ELEMENTS(labels),
2896 sp_spl_tb_t0_value_changed);
2897 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2898 }
2900 /* Reset */
2901 {
2902 InkAction* inky = ink_action_new( "SpiralResetAction",
2903 _("Defaults"),
2904 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2905 GTK_STOCK_CLEAR,
2906 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2907 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2908 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2909 }
2912 sigc::connection *connection = new sigc::connection(
2913 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2914 );
2915 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2916 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2917 }
2919 //########################
2920 //## Pen/Pencil ##
2921 //########################
2924 static void sp_pen_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2925 {
2926 // Put stuff here
2927 }
2929 static void sp_pencil_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* /*mainActions*/, GObject* /*holder*/)
2930 {
2931 // Put stuff here
2932 }
2934 //########################
2935 //## Tweak ##
2936 //########################
2938 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2939 {
2940 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
2941 }
2943 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2944 {
2945 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
2946 }
2948 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
2949 {
2950 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2951 }
2953 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
2954 {
2955 int mode = ege_select_one_action_get_active( act );
2956 prefs_set_int_attribute("tools.tweak", "mode", mode);
2958 GtkAction *doh = GTK_ACTION(g_object_get_data( tbl, "tweak_doh"));
2959 GtkAction *dos = GTK_ACTION(g_object_get_data( tbl, "tweak_dos"));
2960 GtkAction *dol = GTK_ACTION(g_object_get_data( tbl, "tweak_dol"));
2961 GtkAction *doo = GTK_ACTION(g_object_get_data( tbl, "tweak_doo"));
2962 GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
2963 GtkAction *dolabel = GTK_ACTION(g_object_get_data( tbl, "tweak_channels_label"));
2964 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER) {
2965 if (doh) gtk_action_set_sensitive (doh, TRUE);
2966 if (dos) gtk_action_set_sensitive (dos, TRUE);
2967 if (dol) gtk_action_set_sensitive (dol, TRUE);
2968 if (doo) gtk_action_set_sensitive (doo, TRUE);
2969 if (dolabel) gtk_action_set_sensitive (dolabel, TRUE);
2970 if (fid) gtk_action_set_sensitive (fid, FALSE);
2971 } else {
2972 if (doh) gtk_action_set_sensitive (doh, FALSE);
2973 if (dos) gtk_action_set_sensitive (dos, FALSE);
2974 if (dol) gtk_action_set_sensitive (dol, FALSE);
2975 if (doo) gtk_action_set_sensitive (doo, FALSE);
2976 if (dolabel) gtk_action_set_sensitive (dolabel, FALSE);
2977 if (fid) gtk_action_set_sensitive (fid, TRUE);
2978 }
2979 }
2981 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
2982 {
2983 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
2984 }
2986 static void tweak_toggle_doh (GtkToggleAction *act, gpointer /*data*/) {
2987 bool show = gtk_toggle_action_get_active( act );
2988 prefs_set_int_attribute ("tools.tweak", "doh", show ? 1 : 0);
2989 }
2990 static void tweak_toggle_dos (GtkToggleAction *act, gpointer /*data*/) {
2991 bool show = gtk_toggle_action_get_active( act );
2992 prefs_set_int_attribute ("tools.tweak", "dos", show ? 1 : 0);
2993 }
2994 static void tweak_toggle_dol (GtkToggleAction *act, gpointer /*data*/) {
2995 bool show = gtk_toggle_action_get_active( act );
2996 prefs_set_int_attribute ("tools.tweak", "dol", show ? 1 : 0);
2997 }
2998 static void tweak_toggle_doo (GtkToggleAction *act, gpointer /*data*/) {
2999 bool show = gtk_toggle_action_get_active( act );
3000 prefs_set_int_attribute ("tools.tweak", "doo", show ? 1 : 0);
3001 }
3003 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3004 {
3005 {
3006 /* Width */
3007 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
3008 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3009 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
3010 _("Width"), _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
3011 "tools.tweak", "width", 15,
3012 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
3013 1, 100, 1.0, 10.0,
3014 labels, values, G_N_ELEMENTS(labels),
3015 sp_tweak_width_value_changed, 0.01, 0, 100 );
3016 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3017 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3018 }
3021 {
3022 /* Force */
3023 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
3024 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
3025 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
3026 _("Force"), _("Force:"), _("The force of the tweak action"),
3027 "tools.tweak", "force", 20,
3028 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
3029 1, 100, 1.0, 10.0,
3030 labels, values, G_N_ELEMENTS(labels),
3031 sp_tweak_force_value_changed, 0.01, 0, 100 );
3032 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3033 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3034 }
3036 /* Mode */
3037 {
3038 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3040 GtkTreeIter iter;
3041 gtk_list_store_append( model, &iter );
3042 gtk_list_store_set( model, &iter,
3043 0, _("Push mode"),
3044 1, _("Push parts of paths in any direction"),
3045 2, "tweak_push_mode",
3046 -1 );
3048 gtk_list_store_append( model, &iter );
3049 gtk_list_store_set( model, &iter,
3050 0, _("Shrink mode"),
3051 1, _("Shrink (inset) parts of paths"),
3052 2, "tweak_shrink_mode",
3053 -1 );
3055 gtk_list_store_append( model, &iter );
3056 gtk_list_store_set( model, &iter,
3057 0, _("Grow mode"),
3058 1, _("Grow (outset) parts of paths"),
3059 2, "tweak_grow_mode",
3060 -1 );
3062 gtk_list_store_append( model, &iter );
3063 gtk_list_store_set( model, &iter,
3064 0, _("Attract mode"),
3065 1, _("Attract parts of paths towards cursor"),
3066 2, "tweak_attract_mode",
3067 -1 );
3069 gtk_list_store_append( model, &iter );
3070 gtk_list_store_set( model, &iter,
3071 0, _("Repel mode"),
3072 1, _("Repel parts of paths from cursor"),
3073 2, "tweak_repel_mode",
3074 -1 );
3076 gtk_list_store_append( model, &iter );
3077 gtk_list_store_set( model, &iter,
3078 0, _("Roughen mode"),
3079 1, _("Roughen parts of paths"),
3080 2, "tweak_roughen_mode",
3081 -1 );
3083 gtk_list_store_append( model, &iter );
3084 gtk_list_store_set( model, &iter,
3085 0, _("Color paint mode"),
3086 1, _("Paint the tool's color upon selected objects"),
3087 2, "tweak_colorpaint_mode",
3088 -1 );
3090 gtk_list_store_append( model, &iter );
3091 gtk_list_store_set( model, &iter,
3092 0, _("Color jitter mode"),
3093 1, _("Jitter the colors of selected objects"),
3094 2, "tweak_colorjitter_mode",
3095 -1 );
3097 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
3098 g_object_set( act, "short_label", _("Mode:"), NULL );
3099 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3100 g_object_set_data( holder, "mode_action", act );
3102 ege_select_one_action_set_appearance( act, "full" );
3103 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3104 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3105 ege_select_one_action_set_icon_column( act, 2 );
3106 ege_select_one_action_set_tooltip_column( act, 1 );
3108 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3109 ege_select_one_action_set_active( act, mode );
3110 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
3112 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
3113 }
3115 guint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
3117 {
3118 EgeOutputAction* act = ege_output_action_new( "TweakChannelsLabel", _("Channels:"), "", 0 );
3119 ege_output_action_set_use_markup( act, TRUE );
3120 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3121 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3122 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3123 g_object_set_data( holder, "tweak_channels_label", act);
3124 }
3126 {
3127 InkToggleAction* act = ink_toggle_action_new( "TweakDoH",
3128 _("Hue"),
3129 _("In color mode, act on objects' hue"),
3130 NULL,
3131 Inkscape::ICON_SIZE_DECORATION );
3132 g_object_set( act, "short_label", _("H"), NULL );
3133 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3134 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
3135 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doh", 1 ) );
3136 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3137 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3138 g_object_set_data( holder, "tweak_doh", act);
3139 }
3140 {
3141 InkToggleAction* act = ink_toggle_action_new( "TweakDoS",
3142 _("Saturation"),
3143 _("In color mode, act on objects' saturation"),
3144 NULL,
3145 Inkscape::ICON_SIZE_DECORATION );
3146 g_object_set( act, "short_label", _("S"), NULL );
3147 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3148 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
3149 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dos", 1 ) );
3150 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3151 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3152 g_object_set_data( holder, "tweak_dos", act );
3153 }
3154 {
3155 InkToggleAction* act = ink_toggle_action_new( "TweakDoL",
3156 _("Lightness"),
3157 _("In color mode, act on objects' lightness"),
3158 NULL,
3159 Inkscape::ICON_SIZE_DECORATION );
3160 g_object_set( act, "short_label", _("L"), NULL );
3161 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3162 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
3163 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "dol", 1 ) );
3164 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3165 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3166 g_object_set_data( holder, "tweak_dol", act );
3167 }
3168 {
3169 InkToggleAction* act = ink_toggle_action_new( "TweakDoO",
3170 _("Opacity"),
3171 _("In color mode, act on objects' opacity"),
3172 NULL,
3173 Inkscape::ICON_SIZE_DECORATION );
3174 g_object_set( act, "short_label", _("O"), NULL );
3175 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3176 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
3177 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "doo", 1 ) );
3178 if (mode != TWEAK_MODE_COLORPAINT && mode != TWEAK_MODE_COLORJITTER)
3179 gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
3180 g_object_set_data( holder, "tweak_doo", act );
3181 }
3183 { /* Fidelity */
3184 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
3185 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
3186 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
3187 _("Fidelity"), _("Fidelity:"),
3188 _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
3189 "tools.tweak", "fidelity", 50,
3190 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
3191 1, 100, 1.0, 10.0,
3192 labels, values, G_N_ELEMENTS(labels),
3193 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
3194 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3195 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3196 if (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER)
3197 gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
3198 g_object_set_data( holder, "tweak_fidelity", eact );
3199 }
3202 /* Use Pressure button */
3203 {
3204 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
3205 _("Pressure"),
3206 _("Use the pressure of the input device to alter the force of tweak action"),
3207 "use_pressure",
3208 Inkscape::ICON_SIZE_DECORATION );
3209 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3210 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
3211 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
3212 }
3214 }
3217 //########################
3218 //## Calligraphy ##
3219 //########################
3221 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3222 {
3223 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
3224 }
3226 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3227 {
3228 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
3229 }
3231 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3232 {
3233 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
3234 }
3236 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ )
3237 {
3238 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
3239 }
3241 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3242 {
3243 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
3244 }
3246 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3247 {
3248 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
3249 }
3251 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3252 {
3253 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
3254 }
3256 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* /*tbl*/ )
3257 {
3258 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
3259 }
3261 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ )
3262 {
3263 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
3264 }
3266 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer /*data*/ )
3267 {
3268 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
3269 }
3271 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
3272 {
3273 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3275 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
3276 }
3278 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
3279 {
3280 // FIXME: make defaults settable via Inkscape Options
3281 struct KeyValue {
3282 char const *key;
3283 double value;
3284 } const key_values[] = {
3285 {"mass", 0.02},
3286 {"wiggle", 0.0},
3287 {"angle", 30.0},
3288 {"width", 15},
3289 {"thinning", 0.1},
3290 {"tremor", 0.0},
3291 {"flatness", 0.9},
3292 {"cap_rounding", 0.0}
3293 };
3295 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
3296 KeyValue const &kv = key_values[i];
3297 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
3298 if ( adj ) {
3299 gtk_adjustment_set_value(adj, kv.value);
3300 }
3301 }
3302 }
3305 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3306 {
3307 {
3308 EgeAdjustmentAction* calligraphy_angle = 0;
3310 {
3311 /* Width */
3312 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
3313 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
3314 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
3315 _("Pen Width"), _("Width:"),
3316 _("The width of the calligraphic pen (relative to the visible canvas area)"),
3317 "tools.calligraphic", "width", 15,
3318 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
3319 1, 100, 1.0, 10.0,
3320 labels, values, G_N_ELEMENTS(labels),
3321 sp_ddc_width_value_changed, 0.01, 0, 100 );
3322 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3323 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3324 }
3326 {
3327 /* Thinning */
3328 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
3329 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
3330 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
3331 _("Stroke Thinning"), _("Thinning:"),
3332 _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
3333 "tools.calligraphic", "thinning", 0.1,
3334 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3335 -1.0, 1.0, 0.01, 0.1,
3336 labels, values, G_N_ELEMENTS(labels),
3337 sp_ddc_velthin_value_changed, 0.01, 2);
3338 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3339 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3340 }
3342 {
3343 /* Angle */
3344 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
3345 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
3346 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
3347 _("Pen Angle"), _("Angle:"),
3348 _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
3349 "tools.calligraphic", "angle", 30,
3350 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
3351 -90.0, 90.0, 1.0, 10.0,
3352 labels, values, G_N_ELEMENTS(labels),
3353 sp_ddc_angle_value_changed, 1, 0 );
3354 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3355 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3356 calligraphy_angle = eact;
3357 }
3359 {
3360 /* Fixation */
3361 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
3362 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
3363 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
3364 _("Fixation"), _("Fixation:"),
3365 _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
3366 "tools.calligraphic", "flatness", 0.9,
3367 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3368 0.0, 1.0, 0.01, 0.1,
3369 labels, values, G_N_ELEMENTS(labels),
3370 sp_ddc_flatness_value_changed, 0.01, 2 );
3371 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3372 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3373 }
3375 {
3376 /* Cap Rounding */
3377 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
3378 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
3379 // TRANSLATORS: "cap" means "end" (both start and finish) here
3380 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
3381 _("Cap rounding"), _("Caps:"),
3382 _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
3383 "tools.calligraphic", "cap_rounding", 0.0,
3384 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3385 0.0, 5.0, 0.01, 0.1,
3386 labels, values, G_N_ELEMENTS(labels),
3387 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
3388 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3389 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3390 }
3392 {
3393 /* Tremor */
3394 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
3395 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
3396 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
3397 _("Stroke Tremor"), _("Tremor:"),
3398 _("Increase to make strokes rugged and trembling"),
3399 "tools.calligraphic", "tremor", 0.0,
3400 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3401 0.0, 1.0, 0.01, 0.1,
3402 labels, values, G_N_ELEMENTS(labels),
3403 sp_ddc_tremor_value_changed, 0.01, 2 );
3405 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3406 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3407 }
3409 {
3410 /* Wiggle */
3411 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
3412 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
3413 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
3414 _("Pen Wiggle"), _("Wiggle:"),
3415 _("Increase to make the pen waver and wiggle"),
3416 "tools.calligraphic", "wiggle", 0.0,
3417 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3418 0.0, 1.0, 0.01, 0.1,
3419 labels, values, G_N_ELEMENTS(labels),
3420 sp_ddc_wiggle_value_changed, 0.01, 2 );
3421 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3422 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3423 }
3425 {
3426 /* Mass */
3427 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
3428 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
3429 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
3430 _("Pen Mass"), _("Mass:"),
3431 _("Increase to make the pen drag behind, as if slowed by inertia"),
3432 "tools.calligraphic", "mass", 0.02,
3433 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
3434 0.0, 1.0, 0.01, 0.1,
3435 labels, values, G_N_ELEMENTS(labels),
3436 sp_ddc_mass_value_changed, 0.01, 2 );
3437 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3438 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
3439 }
3442 /* Trace Background button */
3443 {
3444 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
3445 _("Trace Background"),
3446 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
3447 "trace_background",
3448 Inkscape::ICON_SIZE_DECORATION );
3449 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3450 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
3451 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
3452 }
3454 /* Use Pressure button */
3455 {
3456 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
3457 _("Pressure"),
3458 _("Use the pressure of the input device to alter the width of the pen"),
3459 "use_pressure",
3460 Inkscape::ICON_SIZE_DECORATION );
3461 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3462 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
3463 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
3464 }
3466 /* Use Tilt button */
3467 {
3468 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
3469 _("Tilt"),
3470 _("Use the tilt of the input device to alter the angle of the pen's nib"),
3471 "use_tilt",
3472 Inkscape::ICON_SIZE_DECORATION );
3473 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3474 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
3475 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3476 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
3477 }
3479 /* Reset */
3480 {
3481 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
3482 _("Defaults"),
3483 _("Reset all parameters to defaults"),
3484 GTK_STOCK_CLEAR );
3485 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
3486 gtk_action_group_add_action( mainActions, act );
3487 gtk_action_set_sensitive( act, TRUE );
3488 }
3489 }
3490 }
3493 //########################
3494 //## Circle / Arc ##
3495 //########################
3497 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
3498 {
3499 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
3500 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
3502 if (v1 == 0 && v2 == 0) {
3503 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
3504 gtk_action_set_sensitive( ocb, FALSE );
3505 gtk_action_set_sensitive( make_whole, FALSE );
3506 }
3507 } else {
3508 gtk_action_set_sensitive( ocb, TRUE );
3509 gtk_action_set_sensitive( make_whole, TRUE );
3510 }
3511 }
3513 static void
3514 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
3515 {
3516 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3518 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3519 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
3520 }
3522 // quit if run by the attr_changed listener
3523 if (g_object_get_data( tbl, "freeze" )) {
3524 return;
3525 }
3527 // in turn, prevent listener from responding
3528 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3530 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
3532 bool modmade = false;
3533 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3534 items != NULL;
3535 items = items->next)
3536 {
3537 SPItem *item = SP_ITEM(items->data);
3539 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
3541 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
3542 SPArc *arc = SP_ARC(item);
3544 if (!strcmp(value_name, "start"))
3545 ge->start = (adj->value * M_PI)/ 180;
3546 else
3547 ge->end = (adj->value * M_PI)/ 180;
3549 sp_genericellipse_normalize(ge);
3550 ((SPObject *)arc)->updateRepr();
3551 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
3553 modmade = true;
3554 }
3555 }
3557 g_free(namespaced_name);
3559 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
3561 sp_arctb_sensitivize( tbl, adj->value, other->value );
3563 if (modmade) {
3564 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
3565 _("Arc: Change start/end"));
3566 }
3568 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3569 }
3572 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
3573 {
3574 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
3575 }
3577 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
3578 {
3579 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
3580 }
3582 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
3583 {
3584 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3585 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3586 if ( ege_select_one_action_get_active( act ) != 0 ) {
3587 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
3588 } else {
3589 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
3590 }
3591 }
3593 // quit if run by the attr_changed listener
3594 if (g_object_get_data( tbl, "freeze" )) {
3595 return;
3596 }
3598 // in turn, prevent listener from responding
3599 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3601 bool modmade = false;
3603 if ( ege_select_one_action_get_active(act) != 0 ) {
3604 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3605 items != NULL;
3606 items = items->next)
3607 {
3608 if (SP_IS_ARC((SPItem *) items->data)) {
3609 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3610 repr->setAttribute("sodipodi:open", "true");
3611 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3612 modmade = true;
3613 }
3614 }
3615 } else {
3616 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3617 items != NULL;
3618 items = items->next)
3619 {
3620 if (SP_IS_ARC((SPItem *) items->data)) {
3621 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3622 repr->setAttribute("sodipodi:open", NULL);
3623 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3624 modmade = true;
3625 }
3626 }
3627 }
3629 if (modmade) {
3630 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
3631 _("Arc: Change open/closed"));
3632 }
3634 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3635 }
3637 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
3638 {
3639 GtkAdjustment *adj;
3640 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
3641 gtk_adjustment_set_value(adj, 0.0);
3642 gtk_adjustment_value_changed(adj);
3644 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
3645 gtk_adjustment_set_value(adj, 0.0);
3646 gtk_adjustment_value_changed(adj);
3648 spinbutton_defocus( GTK_OBJECT(obj) );
3649 }
3651 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const */*name*/,
3652 gchar const */*old_value*/, gchar const */*new_value*/,
3653 bool /*is_interactive*/, gpointer data)
3654 {
3655 GObject *tbl = G_OBJECT(data);
3657 // quit if run by the _changed callbacks
3658 if (g_object_get_data( tbl, "freeze" )) {
3659 return;
3660 }
3662 // in turn, prevent callbacks from responding
3663 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3665 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
3666 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
3668 GtkAdjustment *adj1,*adj2;
3669 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
3670 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
3671 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
3672 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
3674 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
3676 char const *openstr = NULL;
3677 openstr = repr->attribute("sodipodi:open");
3678 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
3680 if (openstr) {
3681 ege_select_one_action_set_active( ocb, 1 );
3682 } else {
3683 ege_select_one_action_set_active( ocb, 0 );
3684 }
3686 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3687 }
3689 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
3690 NULL, /* child_added */
3691 NULL, /* child_removed */
3692 arc_tb_event_attr_changed,
3693 NULL, /* content_changed */
3694 NULL /* order_changed */
3695 };
3698 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3699 {
3700 int n_selected = 0;
3701 Inkscape::XML::Node *repr = NULL;
3703 purge_repr_listener( tbl, tbl );
3705 for (GSList const *items = selection->itemList();
3706 items != NULL;
3707 items = items->next)
3708 {
3709 if (SP_IS_ARC((SPItem *) items->data)) {
3710 n_selected++;
3711 repr = SP_OBJECT_REPR((SPItem *) items->data);
3712 }
3713 }
3715 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3717 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3718 if (n_selected == 0) {
3719 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3720 } else if (n_selected == 1) {
3721 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3722 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3724 if (repr) {
3725 g_object_set_data( tbl, "repr", repr );
3726 Inkscape::GC::anchor(repr);
3727 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
3728 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
3729 }
3730 } else {
3731 // FIXME: implement averaging of all parameters for multiple selected
3732 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3733 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3734 sp_arctb_sensitivize( tbl, 1, 0 );
3735 }
3736 }
3739 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3740 {
3741 EgeAdjustmentAction* eact = 0;
3744 {
3745 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
3746 ege_output_action_set_use_markup( act, TRUE );
3747 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3748 g_object_set_data( holder, "mode_action", act );
3749 }
3751 /* Start */
3752 {
3753 eact = create_adjustment_action( "ArcStartAction",
3754 _("Start"), _("Start:"),
3755 _("The angle (in degrees) from the horizontal to the arc's start point"),
3756 "tools.shapes.arc", "start", 0.0,
3757 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
3758 -360.0, 360.0, 1.0, 10.0,
3759 0, 0, 0,
3760 sp_arctb_start_value_changed);
3761 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3762 }
3764 /* End */
3765 {
3766 eact = create_adjustment_action( "ArcEndAction",
3767 _("End"), _("End:"),
3768 _("The angle (in degrees) from the horizontal to the arc's end point"),
3769 "tools.shapes.arc", "end", 0.0,
3770 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3771 -360.0, 360.0, 1.0, 10.0,
3772 0, 0, 0,
3773 sp_arctb_end_value_changed);
3774 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3775 }
3777 /* Segments / Pie checkbox */
3778 {
3779 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3781 GtkTreeIter iter;
3782 gtk_list_store_append( model, &iter );
3783 gtk_list_store_set( model, &iter,
3784 0, _("Closed arc"),
3785 1, _("Switch to segment (closed shape with two radii)"),
3786 2, "circle_closed_arc",
3787 -1 );
3789 gtk_list_store_append( model, &iter );
3790 gtk_list_store_set( model, &iter,
3791 0, _("Open Arc"),
3792 1, _("Switch to arc (unclosed shape)"),
3793 2, "circle_open_arc",
3794 -1 );
3796 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", (""), (""), NULL, GTK_TREE_MODEL(model) );
3797 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3798 g_object_set_data( holder, "open_action", act );
3800 ege_select_one_action_set_appearance( act, "full" );
3801 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3802 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3803 ege_select_one_action_set_icon_column( act, 2 );
3804 ege_select_one_action_set_tooltip_column( act, 1 );
3806 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
3807 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
3808 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
3809 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
3810 }
3812 /* Make Whole */
3813 {
3814 InkAction* inky = ink_action_new( "ArcResetAction",
3815 _("Make whole"),
3816 _("Make the shape a whole ellipse, not arc or segment"),
3817 "reset_circle",
3818 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3819 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
3820 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3821 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3822 g_object_set_data( holder, "make_whole", inky );
3823 }
3825 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
3826 // sensitivize make whole and open checkbox
3827 {
3828 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
3829 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
3830 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
3831 }
3834 sigc::connection *connection = new sigc::connection(
3835 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
3836 );
3837 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3838 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3839 }
3844 // toggle button callbacks and updaters
3846 //########################
3847 //## Dropper ##
3848 //########################
3850 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
3851 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
3852 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
3853 if ( set_action ) {
3854 if ( gtk_toggle_action_get_active( act ) ) {
3855 gtk_action_set_sensitive( set_action, TRUE );
3856 } else {
3857 gtk_action_set_sensitive( set_action, FALSE );
3858 }
3859 }
3861 spinbutton_defocus(GTK_OBJECT(tbl));
3862 }
3864 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
3865 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3866 spinbutton_defocus(GTK_OBJECT(tbl));
3867 }
3870 /**
3871 * Dropper auxiliary toolbar construction and setup.
3872 *
3873 * TODO: Would like to add swatch of current color.
3874 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3875 * can drag and drop places. Will provide a nice mixing palette.
3876 */
3877 static void sp_dropper_toolbox_prep(SPDesktop */*desktop*/, GtkActionGroup* mainActions, GObject* holder)
3878 {
3879 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
3881 {
3882 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
3883 _("Pick alpha"),
3884 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
3885 "color_alpha_get",
3886 Inkscape::ICON_SIZE_DECORATION );
3887 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3888 g_object_set_data( holder, "pick_action", act );
3889 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
3890 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
3891 }
3893 {
3894 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
3895 _("Set alpha"),
3896 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
3897 "color_alpha_set",
3898 Inkscape::ICON_SIZE_DECORATION );
3899 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3900 g_object_set_data( holder, "set_action", act );
3901 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
3902 // make sure it's disabled if we're not picking alpha
3903 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
3904 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
3905 }
3906 }
3909 //########################
3910 //## Text Toolbox ##
3911 //########################
3912 /*
3913 static void
3914 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3915 {
3916 //Call back for letter sizing spinbutton
3917 }
3919 static void
3920 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3921 {
3922 //Call back for line height spinbutton
3923 }
3925 static void
3926 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3927 {
3928 //Call back for horizontal kerning spinbutton
3929 }
3931 static void
3932 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3933 {
3934 //Call back for vertical kerning spinbutton
3935 }
3937 static void
3938 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3939 {
3940 //Call back for letter rotation spinbutton
3941 }*/
3943 namespace {
3945 bool visible = false;
3947 void
3948 sp_text_toolbox_selection_changed (Inkscape::Selection */*selection*/, GObject *tbl)
3949 {
3950 SPStyle *query =
3951 sp_style_new (SP_ACTIVE_DOCUMENT);
3953 int result_fontspec =
3954 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
3956 int result_family =
3957 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3959 int result_style =
3960 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3962 int result_numbers =
3963 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3965 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3967 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3968 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3969 {
3970 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3972 if (repr)
3973 {
3974 sp_style_read_from_repr (query, repr);
3975 }
3976 else
3977 {
3978 return;
3979 }
3980 }
3982 if (query->text)
3983 {
3984 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3985 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3986 gtk_entry_set_text (GTK_ENTRY (entry), "");
3988 } else if (query->text->font_specification.value || query->text->font_family.value) {
3990 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3992 // Get the font that corresponds
3993 Glib::ustring familyName;
3995 font_instance * font = font_factory::Default()->FaceFromStyle(query);
3996 if (font) {
3997 familyName = font_factory::Default()->GetUIFamilyString(font->descr);
3998 font->Unref();
3999 font = NULL;
4000 }
4002 gtk_entry_set_text (GTK_ENTRY (entry), familyName.c_str());
4004 Gtk::TreePath path;
4005 try {
4006 path = Inkscape::FontLister::get_instance()->get_row_for_font (familyName);
4007 } catch (...) {
4008 g_warning("Family name %s does not have an entry in the font lister.", familyName.c_str());
4009 return;
4010 }
4012 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4013 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4015 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
4017 gtk_tree_selection_select_path (tselection, path.gobj());
4018 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4020 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
4021 }
4023 //Size
4024 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
4025 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
4026 g_object_set_data (tbl, "size-block", gpointer(1));
4027 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
4028 g_object_set_data (tbl, "size-block", gpointer(0));
4029 free (str);
4031 //Anchor
4032 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
4033 {
4034 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
4035 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4036 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4037 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4038 }
4039 else
4040 {
4041 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
4042 {
4043 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
4044 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4045 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4046 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4047 }
4048 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
4049 {
4050 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
4051 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4052 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4053 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4054 }
4055 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
4056 {
4057 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
4058 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4059 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4060 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4061 }
4062 }
4064 //Style
4065 {
4066 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
4068 gboolean active = gtk_toggle_button_get_active (button);
4069 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
4071 if (active != check)
4072 {
4073 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4074 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4075 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4076 }
4077 }
4079 {
4080 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
4082 gboolean active = gtk_toggle_button_get_active (button);
4083 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
4085 if (active != check)
4086 {
4087 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4088 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
4089 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4090 }
4091 }
4093 //Orientation
4094 //locking both buttons, changing one affect all group (both)
4095 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
4096 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
4098 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
4099 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
4101 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
4102 {
4103 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
4104 }
4105 else
4106 {
4107 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
4108 }
4109 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4110 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
4111 }
4113 sp_style_unref(query);
4114 }
4116 void
4117 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint /*flags*/, GObject *tbl)
4118 {
4119 sp_text_toolbox_selection_changed (selection, tbl);
4120 }
4122 void
4123 sp_text_toolbox_subselection_changed (gpointer /*dragger*/, GObject *tbl)
4124 {
4125 sp_text_toolbox_selection_changed (NULL, tbl);
4126 }
4128 void
4129 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
4130 GObject *tbl)
4131 {
4132 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4133 GtkTreeModel *model = 0;
4134 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4135 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4136 GtkTreeIter iter;
4137 char *family = 0;
4139 (void)popdown;
4141 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4142 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4144 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
4145 return;
4146 }
4148 gtk_tree_model_get (model, &iter, 0, &family, -1);
4150 if (g_object_get_data (G_OBJECT (selection), "block"))
4151 {
4152 gtk_entry_set_text (GTK_ENTRY (entry), family);
4153 return;
4154 }
4156 gtk_entry_set_text (GTK_ENTRY (entry), family);
4158 SPStyle *query =
4159 sp_style_new (SP_ACTIVE_DOCUMENT);
4161 int result_fontspec =
4162 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4164 SPCSSAttr *css = sp_repr_css_attr_new ();
4166 std::string fontSpec = query->text->font_specification.value;
4167 if (!fontSpec.empty()) {
4168 Glib::ustring newFontSpec = font_factory::Default()->ReplaceFontSpecificationFamily(fontSpec, family);
4169 if (!newFontSpec.empty() && fontSpec != newFontSpec) {
4170 font_instance *font = font_factory::Default()->FaceFromFontSpecification(newFontSpec.c_str());
4171 if (font) {
4172 sp_repr_css_set_property (css, "-inkscape-font-specification", newFontSpec.c_str());
4174 // Set all the these just in case they were altered when finding the best
4175 // match for the new family and old style...
4177 gchar c[256];
4179 font->Family(c, 256);
4180 sp_repr_css_set_property (css, "font-family", c);
4182 font->Attribute( "weight", c, 256);
4183 sp_repr_css_set_property (css, "font-weight", c);
4185 font->Attribute("style", c, 256);
4186 sp_repr_css_set_property (css, "font-style", c);
4188 font->Attribute("stretch", c, 256);
4189 sp_repr_css_set_property (css, "font-stretch", c);
4191 font->Attribute("variant", c, 256);
4192 sp_repr_css_set_property (css, "font-variant", c);
4194 font->Unref();
4195 }
4196 }
4197 }
4199 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4200 if (result_fontspec == QUERY_STYLE_NOTHING)
4201 {
4202 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4203 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
4204 }
4205 else
4206 {
4207 sp_desktop_set_style (desktop, css, true, true);
4208 }
4210 sp_style_unref(query);
4212 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4213 _("Text: Change font family"));
4214 sp_repr_css_attr_unref (css);
4215 free (family);
4216 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4218 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4219 }
4221 void
4222 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
4223 GObject *tbl)
4224 {
4225 const char *family = gtk_entry_get_text (entry);
4227 try {
4228 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
4229 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
4230 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
4231 gtk_tree_selection_select_path (selection, path.gobj());
4232 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
4233 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4234 } catch (...) {
4235 if (family && strlen (family))
4236 {
4237 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
4238 }
4239 }
4240 }
4242 void
4243 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
4244 gpointer data)
4245 {
4246 if (g_object_get_data (G_OBJECT (button), "block")) return;
4247 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
4248 int prop = GPOINTER_TO_INT(data);
4250 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4251 SPCSSAttr *css = sp_repr_css_attr_new ();
4253 switch (prop)
4254 {
4255 case 0:
4256 {
4257 sp_repr_css_set_property (css, "text-anchor", "start");
4258 sp_repr_css_set_property (css, "text-align", "start");
4259 break;
4260 }
4261 case 1:
4262 {
4263 sp_repr_css_set_property (css, "text-anchor", "middle");
4264 sp_repr_css_set_property (css, "text-align", "center");
4265 break;
4266 }
4268 case 2:
4269 {
4270 sp_repr_css_set_property (css, "text-anchor", "end");
4271 sp_repr_css_set_property (css, "text-align", "end");
4272 break;
4273 }
4275 case 3:
4276 {
4277 sp_repr_css_set_property (css, "text-anchor", "start");
4278 sp_repr_css_set_property (css, "text-align", "justify");
4279 break;
4280 }
4281 }
4283 SPStyle *query =
4284 sp_style_new (SP_ACTIVE_DOCUMENT);
4285 int result_numbers =
4286 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4288 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4289 if (result_numbers == QUERY_STYLE_NOTHING)
4290 {
4291 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4292 }
4294 sp_style_unref(query);
4296 sp_desktop_set_style (desktop, css, true, true);
4297 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4298 _("Text: Change alignment"));
4299 sp_repr_css_attr_unref (css);
4301 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4302 }
4304 void
4305 sp_text_toolbox_style_toggled (GtkToggleButton *button,
4306 gpointer data)
4307 {
4308 if (g_object_get_data (G_OBJECT (button), "block")) return;
4310 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4311 SPCSSAttr *css = sp_repr_css_attr_new ();
4312 int prop = GPOINTER_TO_INT(data);
4313 bool active = gtk_toggle_button_get_active (button);
4315 SPStyle *query =
4316 sp_style_new (SP_ACTIVE_DOCUMENT);
4317 int result_fontspec =
4318 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONT_SPECIFICATION);
4320 Glib::ustring fontSpec = query->text->font_specification.value;
4321 Glib::ustring newFontSpec;
4323 switch (prop)
4324 {
4325 case 0:
4326 {
4327 if (!fontSpec.empty()) {
4328 newFontSpec = font_factory::Default()->FontSpecificationSetBold(fontSpec, active);
4329 }
4330 if (fontSpec != newFontSpec) {
4331 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
4332 }
4333 break;
4334 }
4336 case 1:
4337 {
4338 if (!fontSpec.empty()) {
4339 newFontSpec = font_factory::Default()->FontSpecificationSetItalic(fontSpec, active);
4340 }
4341 if (fontSpec != newFontSpec) {
4342 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
4343 }
4344 break;
4345 }
4346 }
4348 if (!fontSpec.empty()) {
4349 sp_repr_css_set_property (css, "-inkscape-font-specification", fontSpec.c_str());
4350 }
4352 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4353 if (result_fontspec == QUERY_STYLE_NOTHING)
4354 {
4355 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4356 }
4358 sp_style_unref(query);
4360 sp_desktop_set_style (desktop, css, true, true);
4361 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4362 _("Text: Change font style"));
4363 sp_repr_css_attr_unref (css);
4365 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4366 }
4368 void
4369 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
4370 gpointer data)
4371 {
4372 if (g_object_get_data (G_OBJECT (button), "block")) {
4373 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
4374 return;
4375 }
4377 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4378 SPCSSAttr *css = sp_repr_css_attr_new ();
4379 int prop = GPOINTER_TO_INT(data);
4381 switch (prop)
4382 {
4383 case 0:
4384 {
4385 sp_repr_css_set_property (css, "writing-mode", "lr");
4386 break;
4387 }
4389 case 1:
4390 {
4391 sp_repr_css_set_property (css, "writing-mode", "tb");
4392 break;
4393 }
4394 }
4396 SPStyle *query =
4397 sp_style_new (SP_ACTIVE_DOCUMENT);
4398 int result_numbers =
4399 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4401 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4402 if (result_numbers == QUERY_STYLE_NOTHING)
4403 {
4404 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4405 }
4407 sp_desktop_set_style (desktop, css, true, true);
4408 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
4409 _("Text: Change orientation"));
4410 sp_repr_css_attr_unref (css);
4412 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4413 }
4415 gboolean
4416 sp_text_toolbox_size_keypress (GtkWidget */*w*/, GdkEventKey *event, gpointer /*data*/)
4417 {
4418 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4419 if (!desktop) return FALSE;
4421 switch (get_group0_keyval (event)) {
4422 case GDK_Escape: // defocus
4423 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4424 return TRUE; // I consumed the event
4425 break;
4426 case GDK_Return: // defocus
4427 case GDK_KP_Enter:
4428 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4429 return TRUE; // I consumed the event
4430 break;
4431 }
4432 return FALSE;
4433 }
4435 gboolean
4436 sp_text_toolbox_family_keypress (GtkWidget */*w*/, GdkEventKey *event, GObject *tbl)
4437 {
4438 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4439 if (!desktop) return FALSE;
4441 switch (get_group0_keyval (event)) {
4442 case GDK_Escape: // defocus
4443 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4444 sp_text_toolbox_selection_changed (NULL, tbl); // update
4445 return TRUE; // I consumed the event
4446 break;
4447 }
4448 return FALSE;
4449 }
4451 gboolean
4452 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject */*tbl*/)
4453 {
4454 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4455 if (!desktop) return FALSE;
4457 switch (get_group0_keyval (event)) {
4458 case GDK_KP_Enter:
4459 case GDK_Return:
4460 case GDK_Escape: // defocus
4461 gtk_widget_hide (w);
4462 visible = false;
4463 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4464 return TRUE; // I consumed the event
4465 break;
4466 }
4467 return FALSE;
4468 }
4471 void
4472 sp_text_toolbox_size_changed (GtkComboBox *cbox,
4473 GObject *tbl)
4474 {
4475 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4477 if (g_object_get_data (tbl, "size-block")) return;
4479 char *text = gtk_combo_box_get_active_text (cbox);
4481 SPCSSAttr *css = sp_repr_css_attr_new ();
4482 sp_repr_css_set_property (css, "font-size", text);
4483 free (text);
4485 SPStyle *query =
4486 sp_style_new (SP_ACTIVE_DOCUMENT);
4487 int result_numbers =
4488 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
4490 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
4491 if (result_numbers == QUERY_STYLE_NOTHING)
4492 {
4493 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
4494 }
4496 sp_style_unref(query);
4498 sp_desktop_set_style (desktop, css, true, true);
4499 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
4500 _("Text: Change font size"));
4501 sp_repr_css_attr_unref (css);
4504 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
4505 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4506 }
4508 void
4509 sp_text_toolbox_text_popdown_clicked (GtkButton */*button*/,
4510 GObject *tbl)
4511 {
4512 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
4513 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
4514 int x, y;
4516 if (!visible)
4517 {
4518 gdk_window_get_origin (widget->window, &x, &y);
4519 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
4520 gtk_widget_show_all (popdown);
4522 gdk_pointer_grab (widget->window, TRUE,
4523 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
4524 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
4525 GDK_POINTER_MOTION_MASK),
4526 NULL, NULL, GDK_CURRENT_TIME);
4528 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
4530 visible = true;
4531 }
4532 else
4533 {
4534 gdk_pointer_ungrab (GDK_CURRENT_TIME);
4535 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
4536 gtk_widget_hide (popdown);
4537 visible = false;
4538 }
4539 }
4541 gboolean
4542 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
4543 GdkEventFocus */*event*/,
4544 GObject */*tbl*/)
4545 {
4546 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
4547 return FALSE;
4548 }
4550 gboolean
4551 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
4552 GdkEventFocus */*event*/,
4553 GObject */*tbl*/)
4554 {
4555 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
4557 gtk_widget_hide (popdown);
4558 visible = false;
4559 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
4560 return TRUE;
4561 }
4563 void
4564 cell_data_func (GtkTreeViewColumn */*column*/,
4565 GtkCellRenderer *cell,
4566 GtkTreeModel *tree_model,
4567 GtkTreeIter *iter,
4568 gpointer /*data*/)
4569 {
4570 char *family,
4571 *family_escaped,
4572 *sample_escaped;
4574 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
4576 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
4578 family_escaped = g_markup_escape_text (family, -1);
4579 sample_escaped = g_markup_escape_text (sample, -1);
4581 std::stringstream markup;
4582 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
4583 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
4585 free (family);
4586 free (family_escaped);
4587 free (sample_escaped);
4588 }
4590 static void delete_completion(GObject */*obj*/, GtkWidget *entry) {
4591 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
4592 if (completion) {
4593 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
4594 g_object_unref (completion);
4595 }
4596 }
4598 GtkWidget*
4599 sp_text_toolbox_new (SPDesktop *desktop)
4600 {
4601 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
4603 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4604 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4606 GtkTooltips *tt = gtk_tooltips_new();
4607 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4609 ////////////Family
4610 //Window
4611 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4612 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4614 //Entry
4615 GtkWidget *entry = gtk_entry_new ();
4616 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4617 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4618 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4619 gtk_entry_completion_set_text_column (completion, 0);
4620 gtk_entry_completion_set_minimum_key_length (completion, 1);
4621 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4622 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4623 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4624 aux_toolbox_space (tbl, 1);
4625 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
4626 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
4628 //Button
4629 GtkWidget *button = gtk_button_new ();
4630 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
4631 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
4633 //Popdown
4634 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
4635 GtkWidget *treeview = gtk_tree_view_new ();
4637 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4638 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
4639 gtk_tree_view_column_pack_start (column, cell, FALSE);
4640 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
4641 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
4642 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4644 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
4645 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
4646 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
4648 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
4650 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
4651 gtk_container_add (GTK_CONTAINER (sw), treeview);
4653 gtk_container_add (GTK_CONTAINER (window), sw);
4654 gtk_widget_set_size_request (window, 300, 450);
4656 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
4657 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
4658 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
4660 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
4662 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
4663 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
4665 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
4666 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
4668 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
4669 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
4670 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
4671 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
4672 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
4674 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
4675 aux_toolbox_space (tbl, 1);
4676 GtkWidget *box = gtk_event_box_new ();
4677 gtk_container_add (GTK_CONTAINER (box), image);
4678 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
4679 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
4680 GtkTooltips *tooltips = gtk_tooltips_new ();
4681 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
4682 gtk_widget_hide (GTK_WIDGET (box));
4683 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
4685 ////////////Size
4686 const char *sizes[] = {
4687 "4", "6", "8", "9", "10", "11", "12", "13", "14",
4688 "16", "18", "20", "22", "24", "28",
4689 "32", "36", "40", "48", "56", "64", "72", "144"
4690 };
4692 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
4693 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
4694 gtk_widget_set_size_request (cbox, 80, -1);
4695 aux_toolbox_space (tbl, 1);
4696 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
4697 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
4698 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
4699 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
4701 //spacer
4702 aux_toolbox_space (tbl, 4);
4703 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4705 ////////////Text anchor
4706 GtkWidget *group = gtk_radio_button_new (NULL);
4707 GtkWidget *row = gtk_hbox_new (FALSE, 4);
4708 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
4710 // left
4711 GtkWidget *rbutton = group;
4712 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4713 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4714 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4716 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4717 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
4718 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
4719 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
4721 // center
4722 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4723 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4724 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
4725 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4727 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4728 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
4729 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
4730 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
4732 // right
4733 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4734 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4735 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4736 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4738 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4739 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
4740 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
4741 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
4743 // fill
4744 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4745 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4746 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
4747 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4749 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4750 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
4751 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
4752 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
4754 aux_toolbox_space (tbl, 1);
4755 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4757 //spacer
4758 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4760 ////////////Text style
4761 row = gtk_hbox_new (FALSE, 4);
4763 // bold
4764 rbutton = gtk_toggle_button_new ();
4765 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4766 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
4767 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4768 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
4770 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4771 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
4772 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
4774 // italic
4775 rbutton = gtk_toggle_button_new ();
4776 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4777 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
4778 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4779 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
4781 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4782 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
4783 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
4785 aux_toolbox_space (tbl, 1);
4786 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4788 //spacer
4789 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4791 ////////////Text orientation
4792 group = gtk_radio_button_new (NULL);
4793 row = gtk_hbox_new (FALSE, 4);
4794 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4796 // horizontal
4797 rbutton = group;
4798 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4799 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4800 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4801 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4803 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4804 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4805 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4807 // vertical
4808 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4809 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4810 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4811 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4812 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4814 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4815 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4816 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4817 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4820 //watch selection
4821 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4823 sigc::connection *c_selection_changed =
4824 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4825 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4826 pool->add_connection ("selection-changed", c_selection_changed);
4828 sigc::connection *c_selection_modified =
4829 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4830 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4831 pool->add_connection ("selection-modified", c_selection_modified);
4833 sigc::connection *c_subselection_changed =
4834 new sigc::connection (desktop->connectToolSubselectionChanged
4835 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4836 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4838 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4841 gtk_widget_show_all (tbl);
4842 return tbl;
4844 } // end of sp_text_toolbox_new()
4846 }//<unnamed> namespace
4849 //#########################
4850 //## Connector ##
4851 //#########################
4853 static void sp_connector_path_set_avoid(void)
4854 {
4855 cc_selection_set_avoid(true);
4856 }
4859 static void sp_connector_path_set_ignore(void)
4860 {
4861 cc_selection_set_avoid(false);
4862 }
4866 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4867 {
4868 // quit if run by the _changed callbacks
4869 if (g_object_get_data( tbl, "freeze" )) {
4870 return;
4871 }
4873 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4874 SPDocument *doc = sp_desktop_document(desktop);
4876 if (!sp_document_get_undo_sensitive(doc))
4877 {
4878 return;
4879 }
4881 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4883 if ( repr->attribute("inkscape:connector-spacing") ) {
4884 gdouble priorValue = gtk_adjustment_get_value(adj);
4885 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4886 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4887 return;
4888 }
4889 } else if ( adj->value == defaultConnSpacing ) {
4890 return;
4891 }
4893 // in turn, prevent callbacks from responding
4894 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4896 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4897 SP_OBJECT(desktop->namedview)->updateRepr();
4899 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4900 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4901 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4902 NR::Matrix m = NR::identity();
4903 avoid_item_move(&m, item);
4904 }
4906 if (items) {
4907 g_slist_free(items);
4908 }
4910 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4911 _("Change connector spacing"));
4913 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4915 spinbutton_defocus(GTK_OBJECT(tbl));
4916 }
4918 static void sp_connector_graph_layout(void)
4919 {
4920 if (!SP_ACTIVE_DESKTOP) return;
4922 // hack for clones, see comment in align-and-distribute.cpp
4923 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4924 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4926 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4928 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4930 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4931 }
4933 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4934 {
4935 if ( gtk_toggle_action_get_active( act ) ) {
4936 prefs_set_string_attribute("tools.connector", "directedlayout",
4937 "true");
4938 } else {
4939 prefs_set_string_attribute("tools.connector", "directedlayout",
4940 "false");
4941 }
4942 }
4944 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject */*tbl*/ )
4945 {
4946 if ( gtk_toggle_action_get_active( act ) ) {
4947 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4948 "true");
4949 } else {
4950 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4951 "false");
4952 }
4953 }
4956 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4957 {
4958 prefs_set_double_attribute("tools.connector", "length", adj->value);
4959 spinbutton_defocus(GTK_OBJECT(tbl));
4960 }
4962 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4963 gchar const *name, gchar const */*old_value*/, gchar const */*new_value*/,
4964 bool /*is_interactive*/, gpointer data)
4965 {
4966 GtkWidget *tbl = GTK_WIDGET(data);
4968 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4969 return;
4970 }
4971 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4972 return;
4973 }
4975 GtkAdjustment *adj = (GtkAdjustment*)
4976 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4977 gdouble spacing = defaultConnSpacing;
4978 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4980 gtk_adjustment_set_value(adj, spacing);
4981 }
4984 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4985 NULL, /* child_added */
4986 NULL, /* child_removed */
4987 connector_tb_event_attr_changed,
4988 NULL, /* content_changed */
4989 NULL /* order_changed */
4990 };
4993 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
4994 {
4995 {
4996 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
4997 _("Avoid"),
4998 _("Make connectors avoid selected objects"),
4999 "connector_avoid",
5000 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5001 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
5002 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5003 }
5005 {
5006 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
5007 _("Ignore"),
5008 _("Make connectors ignore selected objects"),
5009 "connector_ignore",
5010 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5011 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
5012 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5013 }
5015 EgeAdjustmentAction* eact = 0;
5017 // Spacing spinbox
5018 eact = create_adjustment_action( "ConnectorSpacingAction",
5019 _("Connector Spacing"), _("Spacing:"),
5020 _("The amount of space left around objects by auto-routing connectors"),
5021 "tools.connector", "spacing", defaultConnSpacing,
5022 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
5023 0, 100, 1.0, 10.0,
5024 0, 0, 0,
5025 connector_spacing_changed, 1, 0 );
5026 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5028 // Graph (connector network) layout
5029 {
5030 InkAction* inky = ink_action_new( "ConnectorGraphAction",
5031 _("Graph"),
5032 _("Nicely arrange selected connector network"),
5033 "graph_layout",
5034 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
5035 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
5036 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
5037 }
5039 // Default connector length spinbox
5040 eact = create_adjustment_action( "ConnectorLengthAction",
5041 _("Connector Length"), _("Length:"),
5042 _("Ideal length for connectors when layout is applied"),
5043 "tools.connector", "length", 100,
5044 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
5045 10, 1000, 10.0, 100.0,
5046 0, 0, 0,
5047 connector_length_changed, 1, 0 );
5048 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5051 // Directed edges toggle button
5052 {
5053 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
5054 _("Downwards"),
5055 _("Make connectors with end-markers (arrows) point downwards"),
5056 "directed_graph",
5057 Inkscape::ICON_SIZE_DECORATION );
5058 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5060 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
5061 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5062 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5064 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
5065 }
5067 // Avoid overlaps toggle button
5068 {
5069 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
5070 _("Remove overlaps"),
5071 _("Do not allow overlapping shapes"),
5072 "remove_overlaps",
5073 Inkscape::ICON_SIZE_DECORATION );
5074 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
5076 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
5077 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
5078 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
5080 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
5081 }
5083 // Code to watch for changes to the connector-spacing attribute in
5084 // the XML.
5085 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
5086 g_assert(repr != NULL);
5088 purge_repr_listener( holder, holder );
5090 if (repr) {
5091 g_object_set_data( holder, "repr", repr );
5092 Inkscape::GC::anchor(repr);
5093 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
5094 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
5095 }
5096 } // end of sp_connector_toolbox_prep()
5099 //#########################
5100 //## Paintbucket ##
5101 //#########################
5103 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* /*tbl*/)
5104 {
5105 gint channels = ege_select_one_action_get_active( act );
5106 flood_channels_set_channels( channels );
5107 }
5109 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject */*tbl*/)
5110 {
5111 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
5112 }
5114 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject */*tbl*/)
5115 {
5116 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
5117 }
5119 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
5120 {
5121 UnitTracker* tracker = static_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
5122 SPUnit const *unit = tracker->getActiveUnit();
5124 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
5126 prefs_set_string_attribute("tools.paintbucket", "offsetunits", sp_unit_get_abbreviation(unit));
5127 }
5129 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
5130 {
5131 // FIXME: make defaults settable via Inkscape Options
5132 struct KeyValue {
5133 char const *key;
5134 double value;
5135 } const key_values[] = {
5136 {"threshold", 15},
5137 {"offset", 0.0}
5138 };
5140 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
5141 KeyValue const &kv = key_values[i];
5142 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
5143 if ( adj ) {
5144 gtk_adjustment_set_value(adj, kv.value);
5145 }
5146 }
5148 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
5149 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
5150 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
5151 ege_select_one_action_set_active( autogap_action, 0 );
5152 }
5154 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
5155 {
5156 EgeAdjustmentAction* eact = 0;
5158 {
5159 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5161 GList* items = 0;
5162 gint count = 0;
5163 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
5164 {
5165 GtkTreeIter iter;
5166 gtk_list_store_append( model, &iter );
5167 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5168 count++;
5169 }
5170 g_list_free( items );
5171 items = 0;
5172 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by"), (""), NULL, GTK_TREE_MODEL(model) );
5173 g_object_set( act1, "short_label", _("Fill by:"), NULL );
5174 ege_select_one_action_set_appearance( act1, "compact" );
5175 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
5176 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
5177 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
5178 g_object_set_data( holder, "channels_action", act1 );
5179 }
5181 // Spacing spinbox
5182 {
5183 eact = create_adjustment_action(
5184 "ThresholdAction",
5185 _("Fill Threshold"), _("Threshold:"),
5186 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
5187 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
5188 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
5189 0, 0, 0,
5190 paintbucket_threshold_changed, 1, 0 );
5192 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5193 }
5195 // Create the units menu.
5196 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
5197 tracker->setActiveUnit(sp_unit_get_by_abbreviation(prefs_get_string_attribute("tools.paintbucket", "offsetunits")));
5198 g_object_set_data( holder, "tracker", tracker );
5199 {
5200 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), ("") );
5201 gtk_action_group_add_action( mainActions, act );
5202 }
5204 // Offset spinbox
5205 {
5206 eact = create_adjustment_action(
5207 "OffsetAction",
5208 _("Grow/shrink by"), _("Grow/shrink by:"),
5209 _("The amount to grow (positive) or shrink (negative) the created fill path"),
5210 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
5211 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
5212 0, 0, 0,
5213 paintbucket_offset_changed, 1, 2);
5214 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
5216 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
5217 }
5219 /* Auto Gap */
5220 {
5221 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
5223 GList* items = 0;
5224 gint count = 0;
5225 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
5226 {
5227 GtkTreeIter iter;
5228 gtk_list_store_append( model, &iter );
5229 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
5230 count++;
5231 }
5232 g_list_free( items );
5233 items = 0;
5234 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
5235 g_object_set( act2, "short_label", _("Close gaps:"), NULL );
5236 ege_select_one_action_set_appearance( act2, "compact" );
5237 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
5238 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
5239 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
5240 g_object_set_data( holder, "autogap_action", act2 );
5241 }
5243 /* Reset */
5244 {
5245 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
5246 _("Defaults"),
5247 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
5248 GTK_STOCK_CLEAR );
5249 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
5250 gtk_action_group_add_action( mainActions, act );
5251 gtk_action_set_sensitive( act, TRUE );
5252 }
5254 }
5256 /*
5257 Local Variables:
5258 mode:c++
5259 c-file-style:"stroustrup"
5260 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
5261 indent-tabs-mode:nil
5262 fill-column:99
5263 End:
5264 */
5265 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :