1 #define __SP_MAINTOOLBOX_C__
3 /** \file
4 * Controls bars for some of Inkscape's tools
5 * (for some tools, they are in their own files)
6 */
8 /*
9 *
10 * Authors:
11 * MenTaLguY <mental@rydia.net>
12 * Lauris Kaplinski <lauris@kaplinski.com>
13 * bulia byak <buliabyak@users.sf.net>
14 * Frank Felfe <innerspace@iname.com>
15 * John Cliff <simarilius@yahoo.com>
16 * David Turner <novalis@gnu.org>
17 * Josh Andler <scislac@scislac.com>
18 * Jon A. Cruz <jon@joncruz.org>
19 *
20 * Copyright (C) 2004 David Turner
21 * Copyright (C) 2003 MenTaLguY
22 * Copyright (C) 1999-2006 authors
23 * Copyright (C) 2001-2002 Ximian, Inc.
24 *
25 * Released under GNU GPL, read the file 'COPYING' for more information
26 */
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <gtkmm.h>
33 #include <gtk/gtk.h>
34 #include <iostream>
35 #include <sstream>
37 #include "widgets/button.h"
38 #include "widgets/widget-sizes.h"
39 #include "widgets/spw-utilities.h"
40 #include "widgets/spinbutton-events.h"
41 #include "dialogs/text-edit.h"
43 #include "ui/widget/style-swatch.h"
45 #include "prefs-utils.h"
46 #include "verbs.h"
47 #include "sp-namedview.h"
48 #include "desktop.h"
49 #include "desktop-handles.h"
50 #include "xml/repr.h"
51 #include "xml/node-event-vector.h"
52 #include <glibmm/i18n.h>
53 #include "helper/unit-menu.h"
54 #include "helper/units.h"
56 #include "inkscape.h"
57 #include "conn-avoid-ref.h"
60 #include "select-toolbar.h"
61 #include "gradient-toolbar.h"
63 #include "connector-context.h"
64 #include "node-context.h"
65 #include "shape-editor.h"
66 #include "sp-rect.h"
67 #include "box3d.h"
68 #include "box3d-context.h"
69 #include "sp-star.h"
70 #include "sp-spiral.h"
71 #include "sp-ellipse.h"
72 #include "sp-text.h"
73 #include "sp-flowtext.h"
74 #include "style.h"
75 #include "selection.h"
76 #include "document-private.h"
77 #include "desktop-style.h"
78 #include "../libnrtype/font-lister.h"
79 #include "../connection-pool.h"
80 #include "../prefs-utils.h"
81 #include "../inkscape-stock.h"
82 #include "icon.h"
83 #include "graphlayout/graphlayout.h"
85 #include "mod360.h"
87 #include "toolbox.h"
89 #include "flood-context.h"
91 #include "ink-action.h"
92 #include "ege-adjustment-action.h"
93 #include "ege-output-action.h"
94 #include "ege-select-one-action.h"
95 #include "helper/unit-tracker.h"
97 // FIXME: The next two lines are only temporarily added until
98 // the final resizing behaviour of 3D boxes is sorted out.
99 #include "knotholder.h"
100 SPKnotHolder *sp_3dbox_knot_holder(SPItem *item, SPDesktop *desktop, guint number_of_handles);
102 using Inkscape::UnitTracker;
104 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
105 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
107 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
115 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
117 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
118 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
119 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
120 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
121 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
123 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
126 static struct {
127 gchar const *type_name;
128 gchar const *data_name;
129 sp_verb_t verb;
130 sp_verb_t doubleclick_verb;
131 } const tools[] = {
132 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
133 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
134 { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS },
135 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
136 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
137 // { "SP3DBoxContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
138 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
139 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
140 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
141 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
142 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
143 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
144 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
145 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
146 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
147 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
148 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
149 { NULL, NULL, 0, 0 }
150 };
152 static struct {
153 gchar const *type_name;
154 gchar const *data_name;
155 GtkWidget *(*create_func)(SPDesktop *desktop);
156 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
157 gchar const *ui_name;
158 gint swatch_verb_id;
159 gchar const *swatch_tool;
160 gchar const *swatch_tip;
161 } const aux_toolboxes[] = {
162 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
163 SP_VERB_INVALID, 0, 0},
164 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
165 SP_VERB_INVALID, 0, 0},
166 { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar",
167 SP_VERB_INVALID, 0, 0},
168 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
169 SP_VERB_INVALID, 0, 0},
170 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
171 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
172 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
173 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
174 { "SP3DBoxContext", "3dbox_toolbox", 0, sp_3dbox_toolbox_prep, "3DBoxToolbar",
175 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
176 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
177 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
178 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
179 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
180 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
181 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
182 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
183 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
184 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
185 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
186 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
187 SP_VERB_INVALID, 0, 0},
188 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
189 SP_VERB_INVALID, 0, 0},
190 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
191 SP_VERB_INVALID, 0, 0},
192 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
193 SP_VERB_INVALID, 0, 0},
194 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
195 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
196 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
197 };
200 static gchar const * ui_descr =
201 "<ui>"
202 " <toolbar name='SelectToolbar'>"
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_stroke' />"
221 " <toolitem action='transform_corners' />"
222 " <toolitem action='transform_gradient' />"
223 " <toolitem action='transform_pattern' />"
224 " </toolbar>"
226 " <toolbar name='NodeToolbar'>"
227 " <toolitem action='NodeInsertAction' />"
228 " <toolitem action='NodeDeleteAction' />"
229 " <separator />"
230 " <toolitem action='NodeJoinAction' />"
231 " <toolitem action='NodeJoinSegmentAction' />"
232 " <toolitem action='NodeDeleteSegmentAction' />"
233 " <toolitem action='NodeBreakAction' />"
234 " <separator />"
235 " <toolitem action='NodeCuspAction' />"
236 " <toolitem action='NodeSmoothAction' />"
237 " <toolitem action='NodeSymmetricAction' />"
238 " <separator />"
239 " <toolitem action='NodeLineAction' />"
240 " <toolitem action='NodeCurveAction' />"
241 " <separator />"
242 " <toolitem action='ObjectToPath' />"
243 " <toolitem action='StrokeToPath' />"
244 " <separator />"
245 " <toolitem action='NodesShowHandlesAction' />"
246 " </toolbar>"
248 " <toolbar name='TweakToolbar'>"
249 " <toolitem action='TweakWidthAction' />"
250 " <toolitem action='TweakForceAction' />"
251 " <separator />"
252 " <toolitem action='TweakModeAction' />"
253 " <separator />"
254 " <toolitem action='TweakFidelityAction' />"
255 " <toolitem action='TweakPressureAction' />"
256 " </toolbar>"
258 " <toolbar name='ZoomToolbar'>"
259 " <toolitem action='ZoomIn' />"
260 " <toolitem action='ZoomOut' />"
261 " <separator />"
262 " <toolitem action='ZoomSelection' />"
263 " <toolitem action='ZoomDrawing' />"
264 " <toolitem action='ZoomPage' />"
265 " <toolitem action='ZoomPageWidth' />"
266 " <separator />"
267 " <toolitem action='ZoomPrev' />"
268 " <toolitem action='ZoomNext' />"
269 " <separator />"
270 " <toolitem action='Zoom1:0' />"
271 " <toolitem action='Zoom1:2' />"
272 " <toolitem action='Zoom2:1' />"
273 " </toolbar>"
275 " <toolbar name='StarToolbar'>"
276 " <separator />"
277 " <toolitem action='StarStateAction' />"
278 " <separator />"
279 " <toolitem action='FlatAction' />"
280 " <separator />"
281 " <toolitem action='MagnitudeAction' />"
282 " <toolitem action='SpokeAction' />"
283 " <toolitem action='RoundednessAction' />"
284 " <toolitem action='RandomizationAction' />"
285 " <separator />"
286 " <toolitem action='StarResetAction' />"
287 " </toolbar>"
289 " <toolbar name='RectToolbar'>"
290 " <toolitem action='RectStateAction' />"
291 " <toolitem action='RectWidthAction' />"
292 " <toolitem action='RectHeightAction' />"
293 " <toolitem action='RadiusXAction' />"
294 " <toolitem action='RadiusYAction' />"
295 " <toolitem action='RectUnitsAction' />"
296 " <separator />"
297 " <toolitem action='RectResetAction' />"
298 " </toolbar>"
300 " <toolbar name='3DBoxToolbar'>"
301 " <toolitem action='3DBoxVPXAction' />"
302 " <toolitem action='3DBoxVPYAction' />"
303 " <toolitem action='3DBoxVPZAction' />"
304 " <separator />"
305 " <toolitem action='3DBoxHandlesAction' />"
306 " <separator />"
307 " </toolbar>"
309 " <toolbar name='SpiralToolbar'>"
310 " <toolitem action='SpiralStateAction' />"
311 " <toolitem action='SpiralRevolutionAction' />"
312 " <toolitem action='SpiralExpansionAction' />"
313 " <toolitem action='SpiralT0Action' />"
314 " <separator />"
315 " <toolitem action='SpiralResetAction' />"
316 " </toolbar>"
318 " <toolbar name='PenToolbar'>"
319 " </toolbar>"
321 " <toolbar name='PencilToolbar'>"
322 " </toolbar>"
324 " <toolbar name='CalligraphyToolbar'>"
325 " <separator />"
326 " <toolitem action='CalligraphyWidthAction' />"
327 " <toolitem action='ThinningAction' />"
328 " <separator />"
329 " <toolitem action='AngleAction' />"
330 " <toolitem action='FixationAction' />"
331 " <toolitem action='CapRoundingAction' />"
332 " <separator />"
333 " <toolitem action='TremorAction' />"
334 " <toolitem action='WiggleAction' />"
335 " <toolitem action='MassAction' />"
336 " <separator />"
337 " <toolitem action='TraceAction' />"
338 " <toolitem action='PressureAction' />"
339 " <toolitem action='TiltAction' />"
340 " <toolitem action='CalligraphyResetAction' />"
341 " </toolbar>"
343 " <toolbar name='ArcToolbar'>"
344 " <toolitem action='ArcStateAction' />"
345 " <separator />"
346 " <toolitem action='ArcStartAction' />"
347 " <toolitem action='ArcEndAction' />"
348 " <separator />"
349 " <toolitem action='ArcOpenAction' />"
350 " <separator />"
351 " <toolitem action='ArcResetAction' />"
352 " <separator />"
353 " </toolbar>"
355 " <toolbar name='PaintbucketToolbar'>"
356 " <toolitem action='ChannelsAction' />"
357 " <separator />"
358 " <toolitem action='ThresholdAction' />"
359 " <separator />"
360 " <toolitem action='OffsetAction' />"
361 " <toolitem action='PaintbucketUnitsAction' />"
362 " <separator />"
363 " <toolitem action='AutoGapAction' />"
364 " <separator />"
365 " <toolitem action='PaintbucketResetAction' />"
366 " </toolbar>"
368 " <toolbar name='DropperToolbar'>"
369 " <toolitem action='DropperPickAlphaAction' />"
370 " <toolitem action='DropperSetAlphaAction' />"
371 " </toolbar>"
373 " <toolbar name='ConnectorToolbar'>"
374 " <toolitem action='ConnectorAvoidAction' />"
375 " <toolitem action='ConnectorIgnoreAction' />"
376 " <toolitem action='ConnectorSpacingAction' />"
377 " <toolitem action='ConnectorGraphAction' />"
378 " <toolitem action='ConnectorLengthAction' />"
379 " <toolitem action='ConnectorDirectedAction' />"
380 " <toolitem action='ConnectorOverlapAction' />"
381 " </toolbar>"
383 "</ui>"
384 ;
386 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
388 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
390 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
391 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
393 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
394 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
396 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
397 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
399 /* Global text entry widgets necessary for update */
400 /* GtkWidget *dropper_rgb_entry,
401 *dropper_opacity_entry ; */
402 // should be made a private member once this is converted to class
404 static void delete_connection(GObject *obj, sigc::connection *connection) {
405 connection->disconnect();
406 delete connection;
407 }
409 static void purge_repr_listener( GObject* obj, GObject* tbl )
410 {
411 (void)obj;
412 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
413 if (oldrepr) { // remove old listener
414 sp_repr_remove_listener_by_data(oldrepr, tbl);
415 Inkscape::GC::release(oldrepr);
416 oldrepr = 0;
417 g_object_set_data( tbl, "repr", NULL );
418 }
419 }
421 GtkWidget *
422 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
423 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
424 Inkscape::UI::View::View *view, GtkTooltips *tt)
425 {
426 SPAction *action = verb->get_action(view);
427 if (!action) return NULL;
429 SPAction *doubleclick_action;
430 if (doubleclick_verb)
431 doubleclick_action = doubleclick_verb->get_action(view);
432 else
433 doubleclick_action = NULL;
435 /* fixme: Handle sensitive/unsensitive */
436 /* fixme: Implement sp_button_new_from_action */
437 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
438 gtk_widget_show(b);
439 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
441 return b;
442 }
444 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
445 Inkscape::UI::View::View *view, GtkTooltips *tt)
446 {
447 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
448 }
450 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
451 Inkscape::UI::View::View *view, GtkTooltips *tt)
452 {
453 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
454 }
457 static void trigger_sp_action( GtkAction* act, gpointer user_data )
458 {
459 SPAction* targetAction = SP_ACTION(user_data);
460 if ( targetAction ) {
461 sp_action_perform( targetAction, NULL );
462 }
463 }
465 static void sp_action_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data)
466 {
467 if ( data ) {
468 GtkAction* act = GTK_ACTION(data);
469 gtk_action_set_sensitive( act, sensitive );
470 }
471 }
473 static SPActionEventVector action_event_vector = {
474 {NULL},
475 NULL,
476 NULL,
477 sp_action_action_set_sensitive,
478 NULL,
479 NULL
480 };
482 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
483 {
484 GtkAction* act = 0;
486 SPAction* targetAction = verb->get_action(view);
487 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
488 act = GTK_ACTION(inky);
489 gtk_action_set_sensitive( act, targetAction->sensitive );
491 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
493 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
494 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
496 return act;
497 }
499 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
500 {
501 Inkscape::UI::View::View *view = desktop;
502 gint verbsToUse[] = {
503 // disabled until we have icons for them:
504 //find
505 //SP_VERB_EDIT_TILE,
506 //SP_VERB_EDIT_UNTILE,
507 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
508 SP_VERB_DIALOG_DISPLAY,
509 SP_VERB_DIALOG_FILL_STROKE,
510 SP_VERB_DIALOG_NAMEDVIEW,
511 SP_VERB_DIALOG_TEXT,
512 SP_VERB_DIALOG_XML_EDITOR,
513 SP_VERB_EDIT_CLONE,
514 SP_VERB_EDIT_COPY,
515 SP_VERB_EDIT_CUT,
516 SP_VERB_EDIT_DUPLICATE,
517 SP_VERB_EDIT_PASTE,
518 SP_VERB_EDIT_REDO,
519 SP_VERB_EDIT_UNDO,
520 SP_VERB_EDIT_UNLINK_CLONE,
521 SP_VERB_FILE_EXPORT,
522 SP_VERB_FILE_IMPORT,
523 SP_VERB_FILE_NEW,
524 SP_VERB_FILE_OPEN,
525 SP_VERB_FILE_PRINT,
526 SP_VERB_FILE_SAVE,
527 SP_VERB_OBJECT_TO_CURVE,
528 SP_VERB_SELECTION_GROUP,
529 SP_VERB_SELECTION_OUTLINE,
530 SP_VERB_SELECTION_UNGROUP,
531 SP_VERB_ZOOM_1_1,
532 SP_VERB_ZOOM_1_2,
533 SP_VERB_ZOOM_2_1,
534 SP_VERB_ZOOM_DRAWING,
535 SP_VERB_ZOOM_IN,
536 SP_VERB_ZOOM_NEXT,
537 SP_VERB_ZOOM_OUT,
538 SP_VERB_ZOOM_PAGE,
539 SP_VERB_ZOOM_PAGE_WIDTH,
540 SP_VERB_ZOOM_PREV,
541 SP_VERB_ZOOM_SELECTION,
542 };
544 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
545 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
547 static std::map<SPDesktop*, GtkActionGroup*> groups;
548 GtkActionGroup* mainActions = 0;
549 if ( groups.find(desktop) != groups.end() ) {
550 mainActions = groups[desktop];
551 }
553 if ( !mainActions ) {
554 mainActions = gtk_action_group_new("main");
555 groups[desktop] = mainActions;
556 }
558 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
559 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
560 if ( verb ) {
561 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
562 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
563 gtk_action_group_add_action( mainActions, act );
564 }
565 }
566 }
568 return mainActions;
569 }
572 GtkWidget *
573 sp_tool_toolbox_new()
574 {
575 GtkTooltips *tt = gtk_tooltips_new();
576 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
578 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
579 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
581 gtk_widget_set_sensitive(tb, FALSE);
583 GtkWidget *hb = gtk_handle_box_new();
584 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
585 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
586 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
588 gtk_container_add(GTK_CONTAINER(hb), tb);
589 gtk_widget_show(GTK_WIDGET(tb));
591 sigc::connection* conn = new sigc::connection;
592 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
594 return hb;
595 }
597 static void
598 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
599 {
600 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
601 gtk_widget_queue_resize(child);
602 }
604 static void
605 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
606 {
607 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
608 gtk_widget_queue_resize(child);
609 }
611 GtkWidget *
612 sp_aux_toolbox_new()
613 {
614 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
616 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
617 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
618 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
619 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
620 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
622 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
623 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
625 gtk_widget_set_sensitive(tb, FALSE);
627 GtkWidget *hb = gtk_handle_box_new();
628 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
629 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
630 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
632 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
633 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
635 gtk_container_add(GTK_CONTAINER(hb), tb);
636 gtk_widget_show(GTK_WIDGET(tb));
638 sigc::connection* conn = new sigc::connection;
639 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
641 return hb;
642 }
644 //####################################
645 //# Commands Bar
646 //####################################
648 GtkWidget *
649 sp_commands_toolbox_new()
650 {
651 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
653 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
654 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
655 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
656 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
657 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
659 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
660 gtk_widget_set_sensitive(tb, FALSE);
662 GtkWidget *hb = gtk_handle_box_new();
663 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
664 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
665 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
667 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
668 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
670 gtk_container_add(GTK_CONTAINER(hb), tb);
671 gtk_widget_show(GTK_WIDGET(tb));
673 sigc::connection* conn = new sigc::connection;
674 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
676 return hb;
677 }
680 //####################################
681 //# node editing callbacks
682 //####################################
684 /**
685 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
686 */
687 static ShapeEditor *get_current_shape_editor()
688 {
689 if (!SP_ACTIVE_DESKTOP) {
690 return NULL;
691 }
693 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
695 if (!SP_IS_NODE_CONTEXT(event_context)) {
696 return NULL;
697 }
699 return SP_NODE_CONTEXT(event_context)->shape_editor;
700 }
703 void
704 sp_node_path_edit_add(void)
705 {
706 ShapeEditor *shape_editor = get_current_shape_editor();
707 if (shape_editor) shape_editor->add_node();
708 }
710 void
711 sp_node_path_edit_delete(void)
712 {
713 ShapeEditor *shape_editor = get_current_shape_editor();
714 if (shape_editor) shape_editor->delete_nodes();
715 }
717 void
718 sp_node_path_edit_delete_segment(void)
719 {
720 ShapeEditor *shape_editor = get_current_shape_editor();
721 if (shape_editor) shape_editor->delete_segment();
722 }
724 void
725 sp_node_path_edit_break(void)
726 {
727 ShapeEditor *shape_editor = get_current_shape_editor();
728 if (shape_editor) shape_editor->break_at_nodes();
729 }
731 void
732 sp_node_path_edit_join(void)
733 {
734 ShapeEditor *shape_editor = get_current_shape_editor();
735 if (shape_editor) shape_editor->join_nodes();
736 }
738 void
739 sp_node_path_edit_join_segment(void)
740 {
741 ShapeEditor *shape_editor = get_current_shape_editor();
742 if (shape_editor) shape_editor->join_segments();
743 }
745 void
746 sp_node_path_edit_toline(void)
747 {
748 ShapeEditor *shape_editor = get_current_shape_editor();
749 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
750 }
752 void
753 sp_node_path_edit_tocurve(void)
754 {
755 ShapeEditor *shape_editor = get_current_shape_editor();
756 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
757 }
759 void
760 sp_node_path_edit_cusp(void)
761 {
762 ShapeEditor *shape_editor = get_current_shape_editor();
763 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
764 }
766 void
767 sp_node_path_edit_smooth(void)
768 {
769 ShapeEditor *shape_editor = get_current_shape_editor();
770 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
771 }
773 void
774 sp_node_path_edit_symmetrical(void)
775 {
776 ShapeEditor *shape_editor = get_current_shape_editor();
777 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
778 }
780 static void toggle_show_handles (GtkToggleAction *act, gpointer data) {
781 bool show = gtk_toggle_action_get_active( act );
782 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
783 ShapeEditor *shape_editor = get_current_shape_editor();
784 if (shape_editor) shape_editor->show_handles(show);
785 }
787 //################################
788 //## Node Editing Toolbox ##
789 //################################
791 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
792 {
793 {
794 InkAction* inky = ink_action_new( "NodeInsertAction",
795 _("Insert"),
796 _("Insert new nodes into selected segments"),
797 "node_insert",
798 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
799 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
800 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
801 }
803 {
804 InkAction* inky = ink_action_new( "NodeDeleteAction",
805 _("Delete"),
806 _("Delete selected nodes"),
807 "node_delete",
808 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
809 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
810 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
811 }
813 {
814 InkAction* inky = ink_action_new( "NodeJoinAction",
815 _("Join"),
816 _("Join selected endnodes"),
817 "node_join",
818 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
819 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
820 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
821 }
823 {
824 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
825 _("Join Segment"),
826 _("Join selected endnodes with a new segment"),
827 "node_join_segment",
828 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
829 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
830 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
831 }
833 {
834 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
835 _("Delete Segment"),
836 _("Split path between two non-endpoint nodes"),
837 "node_delete_segment",
838 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
839 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
840 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
841 }
843 {
844 InkAction* inky = ink_action_new( "NodeBreakAction",
845 _("Node Break"),
846 _("Break path at selected nodes"),
847 "node_break",
848 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
849 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
850 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
851 }
853 {
854 InkAction* inky = ink_action_new( "NodeCuspAction",
855 _("Node Cusp"),
856 _("Make selected nodes corner"),
857 "node_cusp",
858 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
859 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
860 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
861 }
863 {
864 InkAction* inky = ink_action_new( "NodeSmoothAction",
865 _("Node Smooth"),
866 _("Make selected nodes smooth"),
867 "node_smooth",
868 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
869 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
870 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
871 }
873 {
874 InkAction* inky = ink_action_new( "NodeSymmetricAction",
875 _("Node Symmetric"),
876 _("Make selected nodes symmetric"),
877 "node_symmetric",
878 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
879 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
880 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
881 }
883 {
884 InkAction* inky = ink_action_new( "NodeLineAction",
885 _("Node Line"),
886 _("Make selected segments lines"),
887 "node_line",
888 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
889 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
890 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
891 }
893 {
894 InkAction* inky = ink_action_new( "NodeCurveAction",
895 _("Node Curve"),
896 _("Make selected segments curves"),
897 "node_curve",
898 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
899 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
900 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
901 }
903 {
904 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
905 _("Show Handles"),
906 _("Show the Bezier handles of selected nodes"),
907 "nodes_show_handles",
908 Inkscape::ICON_SIZE_DECORATION );
909 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
910 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
911 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
912 }
914 } // end of sp_node_toolbox_prep()
917 //########################
918 //## Zoom Toolbox ##
919 //########################
921 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
922 {
923 // no custom GtkAction setup needed
924 } // end of sp_zoom_toolbox_prep()
926 void
927 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
928 {
929 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")));
930 }
933 void
934 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
935 {
936 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")));
937 }
939 void
940 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
941 {
942 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")));
943 }
945 static void
946 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
947 {
948 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
949 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
951 if (old_desktop) {
952 GList *children, *iter;
954 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
955 for ( iter = children ; iter ; iter = iter->next ) {
956 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
957 }
958 g_list_free(children);
959 }
961 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
963 if (desktop) {
964 gtk_widget_set_sensitive(toolbox, TRUE);
965 setup_func(toolbox, desktop);
966 update_func(desktop, desktop->event_context, toolbox);
967 *conn = desktop->connectEventContextChanged
968 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
969 } else {
970 gtk_widget_set_sensitive(toolbox, FALSE);
971 }
973 } // end of toolbox_set_desktop()
976 static void
977 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
978 {
979 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
980 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
981 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
982 // "toolbox.tools" was not set. Fallback to older value
983 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
985 // Copy the setting forwards
986 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
987 }
988 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
990 for (int i = 0 ; tools[i].type_name ; i++ ) {
991 GtkWidget *button =
992 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
993 SP_BUTTON_TYPE_TOGGLE,
994 Inkscape::Verb::get(tools[i].verb),
995 Inkscape::Verb::get(tools[i].doubleclick_verb),
996 desktop,
997 tooltips );
999 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
1000 (gpointer)button );
1001 }
1002 }
1005 static void
1006 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
1007 {
1008 gchar const *const tname = ( eventcontext
1009 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1010 : NULL );
1011 for (int i = 0 ; tools[i].type_name ; i++ ) {
1012 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
1013 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
1014 }
1015 }
1017 static void
1018 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1019 {
1020 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
1021 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1022 GtkUIManager* mgr = gtk_ui_manager_new();
1023 GError* errVal = 0;
1024 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1025 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1027 std::map<std::string, GtkWidget*> dataHolders;
1029 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1030 if ( aux_toolboxes[i].prep_func ) {
1031 // converted to GtkActions and UIManager
1033 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1034 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1035 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1036 dataHolders[aux_toolboxes[i].type_name] = kludge;
1037 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1038 } else {
1040 GtkWidget *sub_toolbox = 0;
1041 if (aux_toolboxes[i].create_func == NULL)
1042 sub_toolbox = sp_empty_toolbox_new(desktop);
1043 else {
1044 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1045 }
1047 gtk_size_group_add_widget( grouper, sub_toolbox );
1049 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1050 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1052 }
1053 }
1055 // Second pass to create toolbars *after* all GtkActions are created
1056 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1057 if ( aux_toolboxes[i].prep_func ) {
1058 // converted to GtkActions and UIManager
1060 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1062 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1063 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1065 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1066 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1067 g_free( tmp );
1068 tmp = 0;
1070 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1071 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1072 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1073 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1074 }
1075 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1078 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1080 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1081 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1082 swatch->setDesktop( desktop );
1083 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1084 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1085 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1086 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 );
1087 }
1089 gtk_widget_show_all( holder );
1090 sp_set_font_size_smaller( holder );
1092 gtk_size_group_add_widget( grouper, holder );
1094 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1095 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1096 }
1097 }
1099 g_object_unref( G_OBJECT(grouper) );
1100 }
1102 static void
1103 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1104 {
1105 gchar const *tname = ( eventcontext
1106 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1107 : NULL );
1108 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1109 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1110 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1111 gtk_widget_show_all(sub_toolbox);
1112 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1113 } else {
1114 gtk_widget_hide(sub_toolbox);
1115 }
1116 }
1117 }
1119 static void
1120 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1121 {
1122 gchar const * descr =
1123 "<ui>"
1124 " <toolbar name='CommandsToolbar'>"
1125 " <toolitem action='FileNew' />"
1126 " <toolitem action='FileOpen' />"
1127 " <toolitem action='FileSave' />"
1128 " <toolitem action='FilePrint' />"
1129 " <separator />"
1130 " <toolitem action='FileImport' />"
1131 " <toolitem action='FileExport' />"
1132 " <separator />"
1133 " <toolitem action='EditUndo' />"
1134 " <toolitem action='EditRedo' />"
1135 " <separator />"
1136 " <toolitem action='EditCopy' />"
1137 " <toolitem action='EditCut' />"
1138 " <toolitem action='EditPaste' />"
1139 " <separator />"
1140 " <toolitem action='ZoomSelection' />"
1141 " <toolitem action='ZoomDrawing' />"
1142 " <toolitem action='ZoomPage' />"
1143 " <separator />"
1144 " <toolitem action='EditDuplicate' />"
1145 " <toolitem action='EditClone' />"
1146 " <toolitem action='EditUnlinkClone' />"
1147 " <separator />"
1148 " <toolitem action='SelectionGroup' />"
1149 " <toolitem action='SelectionUnGroup' />"
1150 " <separator />"
1151 " <toolitem action='DialogFillStroke' />"
1152 " <toolitem action='DialogText' />"
1153 " <toolitem action='DialogXMLEditor' />"
1154 " <toolitem action='DialogAlignDistribute' />"
1155 " <separator />"
1156 " <toolitem action='DialogPreferences' />"
1157 " <toolitem action='DialogDocumentProperties' />"
1158 " </toolbar>"
1159 "</ui>";
1160 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1163 GtkUIManager* mgr = gtk_ui_manager_new();
1164 GError* errVal = 0;
1166 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1167 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1169 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1170 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1171 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1172 }
1173 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1174 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1175 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1178 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1179 }
1181 static void
1182 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1183 {
1184 }
1186 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1187 {
1188 gtk_widget_show(toolbox_toplevel);
1189 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1191 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1192 if (!shown_toolbox) {
1193 return;
1194 }
1195 gtk_widget_show(toolbox);
1197 // need to show the spacer, or the padding will be off
1198 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1199 gtk_widget_show(spacer);
1201 gtk_widget_show_all(shown_toolbox);
1202 }
1204 void
1205 aux_toolbox_space(GtkWidget *tb, gint space)
1206 {
1207 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1208 }
1210 static GtkWidget *
1211 sp_empty_toolbox_new(SPDesktop *desktop)
1212 {
1213 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1214 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1215 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1217 gtk_widget_show_all(tbl);
1218 sp_set_font_size_smaller (tbl);
1220 return tbl;
1221 }
1223 // helper UI functions
1225 GtkWidget *
1226 sp_tb_spinbutton(
1227 gchar *label, gchar const *tooltip,
1228 gchar const *path, gchar const *data, gdouble def,
1229 GtkWidget *us,
1230 GtkWidget *tbl,
1231 gboolean altx, gchar const *altx_mark,
1232 gdouble lower, gdouble upper, gdouble step, gdouble page,
1233 void (*callback)(GtkAdjustment *, GtkWidget *),
1234 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1235 {
1236 GtkTooltips *tt = gtk_tooltips_new();
1238 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1240 GtkWidget *l = gtk_label_new(label);
1241 gtk_widget_show(l);
1242 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1243 gtk_container_add(GTK_CONTAINER(hb), l);
1245 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1246 lower, upper, step, page, page);
1247 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1248 if (us)
1249 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1251 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1252 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1253 if (altx)
1254 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1255 gtk_widget_set_size_request(sb,
1256 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1257 AUX_SPINBUTTON_HEIGHT);
1258 gtk_widget_show(sb);
1259 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1260 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1261 gtk_container_add(GTK_CONTAINER(hb), sb);
1262 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1264 return hb;
1265 }
1267 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
1268 gchar const *label, gchar const *tooltip,
1269 gchar const *path, gchar const *data, gdouble def,
1270 GtkWidget *focusTarget,
1271 GtkWidget *us,
1272 GObject *dataKludge,
1273 gboolean altx, gchar const *altx_mark,
1274 gdouble lower, gdouble upper, gdouble step, gdouble page,
1275 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
1276 void (*callback)(GtkAdjustment *, GObject *),
1277 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
1278 {
1279 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
1280 lower, upper, step, page, page ) );
1281 if (us) {
1282 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
1283 }
1285 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
1287 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
1289 if ( (descrCount > 0) && descrLabels && descrValues ) {
1290 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
1291 }
1293 if ( focusTarget ) {
1294 ege_adjustment_action_set_focuswidget( act, focusTarget );
1295 }
1297 if ( altx && altx_mark ) {
1298 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
1299 }
1301 if ( dataKludge ) {
1302 g_object_set_data( dataKludge, data, adj );
1303 }
1305 // Using a cast just to make sure we pass in the right kind of function pointer
1306 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
1308 return act;
1309 }
1312 #define MODE_LABEL_WIDTH 70
1314 //########################
1315 //## Star ##
1316 //########################
1318 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1319 {
1320 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1322 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1323 // do not remember prefs if this call is initiated by an undo change, because undoing object
1324 // creation sets bogus values to its attributes before it is deleted
1325 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1326 }
1328 // quit if run by the attr_changed listener
1329 if (g_object_get_data( dataKludge, "freeze" )) {
1330 return;
1331 }
1333 // in turn, prevent listener from responding
1334 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1336 bool modmade = false;
1338 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1339 GSList const *items = selection->itemList();
1340 for (; items != NULL; items = items->next) {
1341 if (SP_IS_STAR((SPItem *) items->data)) {
1342 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1343 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1344 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1345 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1346 + M_PI / (gint)adj->value));
1347 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1348 modmade = true;
1349 }
1350 }
1351 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1352 _("Star: Change number of corners"));
1354 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1355 }
1357 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1358 {
1359 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1361 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1362 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1363 }
1365 // quit if run by the attr_changed listener
1366 if (g_object_get_data( dataKludge, "freeze" )) {
1367 return;
1368 }
1370 // in turn, prevent listener from responding
1371 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1373 bool modmade = false;
1374 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1375 GSList const *items = selection->itemList();
1376 for (; items != NULL; items = items->next) {
1377 if (SP_IS_STAR((SPItem *) items->data)) {
1378 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1380 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1381 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1382 if (r2 < r1) {
1383 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1384 } else {
1385 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1386 }
1388 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1389 modmade = true;
1390 }
1391 }
1393 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1394 _("Star: Change spoke ratio"));
1396 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1397 }
1399 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1400 {
1401 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1402 bool flat = ege_select_one_action_get_active( act ) == 0;
1404 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1405 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1406 flat ? "true" : "false" );
1407 }
1409 // quit if run by the attr_changed listener
1410 if (g_object_get_data( dataKludge, "freeze" )) {
1411 return;
1412 }
1414 // in turn, prevent listener from responding
1415 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1417 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1418 GSList const *items = selection->itemList();
1419 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1420 bool modmade = false;
1422 if ( prop_action ) {
1423 gtk_action_set_sensitive( prop_action, !flat );
1424 }
1426 for (; items != NULL; items = items->next) {
1427 if (SP_IS_STAR((SPItem *) items->data)) {
1428 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1429 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1430 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1431 modmade = true;
1432 }
1433 }
1435 if (modmade) {
1436 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1437 flat ? _("Make polygon") : _("Make star"));
1438 }
1440 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1441 }
1443 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1444 {
1445 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1447 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1448 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1449 }
1451 // quit if run by the attr_changed listener
1452 if (g_object_get_data( dataKludge, "freeze" )) {
1453 return;
1454 }
1456 // in turn, prevent listener from responding
1457 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1459 bool modmade = false;
1461 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1462 GSList const *items = selection->itemList();
1463 for (; items != NULL; items = items->next) {
1464 if (SP_IS_STAR((SPItem *) items->data)) {
1465 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1466 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1467 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1468 modmade = true;
1469 }
1470 }
1471 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1472 _("Star: Change rounding"));
1474 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1475 }
1477 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1478 {
1479 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1481 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1482 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1483 }
1485 // quit if run by the attr_changed listener
1486 if (g_object_get_data( dataKludge, "freeze" )) {
1487 return;
1488 }
1490 // in turn, prevent listener from responding
1491 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1493 bool modmade = false;
1495 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1496 GSList const *items = selection->itemList();
1497 for (; items != NULL; items = items->next) {
1498 if (SP_IS_STAR((SPItem *) items->data)) {
1499 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1500 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1501 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1502 modmade = true;
1503 }
1504 }
1505 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1506 _("Star: Change randomization"));
1508 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1509 }
1512 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1513 gchar const *old_value, gchar const *new_value,
1514 bool is_interactive, gpointer data)
1515 {
1516 GtkWidget *tbl = GTK_WIDGET(data);
1518 // quit if run by the _changed callbacks
1519 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1520 return;
1521 }
1523 // in turn, prevent callbacks from responding
1524 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1526 GtkAdjustment *adj = 0;
1528 if (!strcmp(name, "inkscape:randomized")) {
1529 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1530 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1531 } else if (!strcmp(name, "inkscape:rounded")) {
1532 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1533 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1534 } else if (!strcmp(name, "inkscape:flatsided")) {
1535 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1536 char const *flatsides = repr->attribute("inkscape:flatsided");
1537 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1538 if ( flatsides && !strcmp(flatsides,"false") ) {
1539 ege_select_one_action_set_active( flat_action, 1 );
1540 gtk_action_set_sensitive( prop_action, TRUE );
1541 } else {
1542 ege_select_one_action_set_active( flat_action, 0 );
1543 gtk_action_set_sensitive( prop_action, FALSE );
1544 }
1545 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1546 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1547 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1548 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1549 if (r2 < r1) {
1550 gtk_adjustment_set_value(adj, r2/r1);
1551 } else {
1552 gtk_adjustment_set_value(adj, r1/r2);
1553 }
1554 } else if (!strcmp(name, "sodipodi:sides")) {
1555 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1556 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1557 }
1559 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1560 }
1563 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1564 {
1565 NULL, /* child_added */
1566 NULL, /* child_removed */
1567 star_tb_event_attr_changed,
1568 NULL, /* content_changed */
1569 NULL /* order_changed */
1570 };
1573 /**
1574 * \param selection Should not be NULL.
1575 */
1576 static void
1577 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1578 {
1579 int n_selected = 0;
1580 Inkscape::XML::Node *repr = NULL;
1582 purge_repr_listener( tbl, tbl );
1584 for (GSList const *items = selection->itemList();
1585 items != NULL;
1586 items = items->next)
1587 {
1588 if (SP_IS_STAR((SPItem *) items->data)) {
1589 n_selected++;
1590 repr = SP_OBJECT_REPR((SPItem *) items->data);
1591 }
1592 }
1594 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1596 if (n_selected == 0) {
1597 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1598 } else if (n_selected == 1) {
1599 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1601 if (repr) {
1602 g_object_set_data( tbl, "repr", repr );
1603 Inkscape::GC::anchor(repr);
1604 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1605 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1606 }
1607 } else {
1608 // FIXME: implement averaging of all parameters for multiple selected stars
1609 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1610 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1611 }
1612 }
1615 static void sp_stb_defaults( GtkWidget *widget, GObject *dataKludge )
1616 {
1617 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1618 // callbacks to lump all the changes for all selected objects in one undo step
1620 GtkAdjustment *adj = 0;
1622 // fixme: make settable in prefs!
1623 gint mag = 5;
1624 gdouble prop = 0.5;
1625 gboolean flat = FALSE;
1626 gdouble randomized = 0;
1627 gdouble rounded = 0;
1629 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1630 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1632 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1633 gtk_action_set_sensitive( sb2, !flat );
1635 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1636 gtk_adjustment_set_value(adj, mag);
1637 gtk_adjustment_value_changed(adj);
1639 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1640 gtk_adjustment_set_value(adj, prop);
1641 gtk_adjustment_value_changed(adj);
1643 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1644 gtk_adjustment_set_value(adj, rounded);
1645 gtk_adjustment_value_changed(adj);
1647 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1648 gtk_adjustment_set_value(adj, randomized);
1649 gtk_adjustment_value_changed(adj);
1650 }
1653 void
1654 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1655 {
1656 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1657 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1658 GtkWidget *l = gtk_label_new(NULL);
1659 gtk_label_set_markup(GTK_LABEL(l), title);
1660 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1661 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1662 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1663 }
1666 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1667 {
1668 {
1669 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1670 ege_output_action_set_use_markup( act, TRUE );
1671 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1672 g_object_set_data( holder, "mode_action", act );
1673 }
1675 {
1676 //EgeAdjustmentAction* calligraphy_angle = 0;
1677 EgeAdjustmentAction* eact = 0;
1678 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1679 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1681 /* Flatsided checkbox */
1682 {
1683 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1685 GtkTreeIter iter;
1686 gtk_list_store_append( model, &iter );
1687 gtk_list_store_set( model, &iter,
1688 0, _("Polygon"),
1689 1, _("Regular polygon (with one handle) instead of a star"),
1690 2, "star_flat",
1691 -1 );
1693 gtk_list_store_append( model, &iter );
1694 gtk_list_store_set( model, &iter,
1695 0, _("Star"),
1696 1, _("Star instead of a regular polygon (with one handle)"),
1697 2, "star_angled",
1698 -1 );
1700 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
1701 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1702 g_object_set_data( holder, "flat_action", act );
1704 ege_select_one_action_set_appearance( act, "full" );
1705 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1706 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1707 ege_select_one_action_set_icon_column( act, 2 );
1708 ege_select_one_action_set_tooltip_column( act, 1 );
1710 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1711 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1712 }
1714 /* Magnitude */
1715 //gchar const* labels[] = {_("tri (default)"), _("quad"), _("pent")};
1716 //gdouble values[] = {3, 4, 5};
1717 eact = create_adjustment_action( "MagnitudeAction",
1718 _("Corners:"), _("Number of corners of a polygon or star"),
1719 "tools.shapes.star", "magnitude", 3,
1720 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1721 3, 1024, 1, 5,
1722 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
1723 sp_stb_magnitude_value_changed,
1724 1.0, 0 );
1725 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1726 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1728 /* Spoke ratio */
1729 //gchar const* labels2[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1730 //gdouble values2[] = {-90, 0, 30, 90};
1731 eact = create_adjustment_action( "SpokeAction",
1732 _("Spoke ratio:"),
1733 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1734 // Base radius is the same for the closest handle.
1735 _("Base radius to tip radius ratio"),
1736 "tools.shapes.star", "proportion", 0.5,
1737 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1738 0.01, 1.0, 0.01, 0.1,
1739 0, 0, 0, // labels2, values2, G_N_ELEMENTS(labels2),
1740 sp_stb_proportion_value_changed );
1741 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1742 g_object_set_data( holder, "prop_action", eact );
1744 if ( !isFlatSided ) {
1745 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1746 } else {
1747 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1748 }
1750 /* Roundedness */
1751 //gchar const* labels3[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1752 //gdouble values3[] = {-90, 0, 30, 90};
1753 eact = create_adjustment_action( "RoundednessAction",
1754 _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1755 "tools.shapes.star", "rounded", 0.0,
1756 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1757 -100.0, 100.0, 0.01, 0.1,
1758 0, 0, 0, // labels3, values3, G_N_ELEMENTS(labels3),
1759 sp_stb_rounded_value_changed );
1760 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1761 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1763 /* Randomization */
1764 //gchar const* labels4[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1765 //gdouble values4[] = {-90, 0, 30, 90};
1766 eact = create_adjustment_action( "RandomizationAction",
1767 _("Randomized:"), _("Scatter randomly the corners and angles"),
1768 "tools.shapes.star", "randomized", 0.0,
1769 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1770 -10.0, 10.0, 0.001, 0.01,
1771 0, 0, 0, // labels4, values4, G_N_ELEMENTS(labels4),
1772 sp_stb_randomized_value_changed, 0.1, 3 );
1773 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1774 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1775 }
1777 {
1778 /* Reset */
1779 {
1780 GtkAction* act = gtk_action_new( "StarResetAction",
1781 _("Defaults"),
1782 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1783 GTK_STOCK_CLEAR );
1784 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1785 gtk_action_group_add_action( mainActions, act );
1786 gtk_action_set_sensitive( act, TRUE );
1787 }
1788 }
1790 sigc::connection *connection = new sigc::connection(
1791 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1792 );
1793 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1794 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1795 }
1798 //########################
1799 //## Rect ##
1800 //########################
1802 static void sp_rtb_sensitivize( GObject *tbl )
1803 {
1804 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
1805 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
1806 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
1808 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
1809 gtk_action_set_sensitive( not_rounded, FALSE );
1810 } else {
1811 gtk_action_set_sensitive( not_rounded, TRUE );
1812 }
1813 }
1816 static void
1817 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
1818 void (*setter)(SPRect *, gdouble))
1819 {
1820 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1822 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1823 SPUnit const *unit = tracker->getActiveUnit();
1825 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1826 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1827 }
1829 // quit if run by the attr_changed listener
1830 if (g_object_get_data( tbl, "freeze" )) {
1831 return;
1832 }
1834 // in turn, prevent listener from responding
1835 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1837 bool modmade = false;
1838 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1839 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1840 if (SP_IS_RECT(items->data)) {
1841 if (adj->value != 0) {
1842 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1843 } else {
1844 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1845 }
1846 modmade = true;
1847 }
1848 }
1850 sp_rtb_sensitivize( tbl );
1852 if (modmade) {
1853 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
1854 _("Change rectangle"));
1855 }
1857 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1858 }
1860 static void
1861 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
1862 {
1863 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1864 }
1866 static void
1867 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
1868 {
1869 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1870 }
1872 static void
1873 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
1874 {
1875 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1876 }
1878 static void
1879 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
1880 {
1881 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1882 }
1886 static void
1887 sp_rtb_defaults( GtkWidget *widget, GObject *obj)
1888 {
1889 GtkAdjustment *adj = 0;
1891 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
1892 gtk_adjustment_set_value(adj, 0.0);
1893 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1894 gtk_adjustment_value_changed(adj);
1896 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
1897 gtk_adjustment_set_value(adj, 0.0);
1898 gtk_adjustment_value_changed(adj);
1900 sp_rtb_sensitivize( obj );
1901 }
1903 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1904 gchar const *old_value, gchar const *new_value,
1905 bool is_interactive, gpointer data)
1906 {
1907 GObject *tbl = G_OBJECT(data);
1909 // quit if run by the _changed callbacks
1910 if (g_object_get_data( tbl, "freeze" )) {
1911 return;
1912 }
1914 // in turn, prevent callbacks from responding
1915 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
1917 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1918 SPUnit const *unit = tracker->getActiveUnit();
1920 gpointer item = g_object_get_data( tbl, "item" );
1921 if (item && SP_IS_RECT(item)) {
1922 {
1923 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
1924 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1925 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1926 }
1928 {
1929 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
1930 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1931 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1932 }
1934 {
1935 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
1936 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1937 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1938 }
1940 {
1941 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
1942 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1943 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1944 }
1945 }
1947 sp_rtb_sensitivize( tbl );
1949 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1950 }
1953 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1954 NULL, /* child_added */
1955 NULL, /* child_removed */
1956 rect_tb_event_attr_changed,
1957 NULL, /* content_changed */
1958 NULL /* order_changed */
1959 };
1961 /**
1962 * \param selection should not be NULL.
1963 */
1964 static void
1965 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1966 {
1967 int n_selected = 0;
1968 Inkscape::XML::Node *repr = NULL;
1969 SPItem *item = NULL;
1971 if ( g_object_get_data( tbl, "repr" ) ) {
1972 g_object_set_data( tbl, "item", NULL );
1973 }
1974 purge_repr_listener( tbl, tbl );
1976 for (GSList const *items = selection->itemList();
1977 items != NULL;
1978 items = items->next) {
1979 if (SP_IS_RECT((SPItem *) items->data)) {
1980 n_selected++;
1981 item = (SPItem *) items->data;
1982 repr = SP_OBJECT_REPR(item);
1983 }
1984 }
1986 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1988 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
1990 if (n_selected == 0) {
1991 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1993 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1994 gtk_action_set_sensitive(w, FALSE);
1995 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1996 gtk_action_set_sensitive(h, FALSE);
1998 } else if (n_selected == 1) {
1999 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2000 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2002 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
2003 gtk_action_set_sensitive(w, TRUE);
2004 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
2005 gtk_action_set_sensitive(h, TRUE);
2007 if (repr) {
2008 g_object_set_data( tbl, "repr", repr );
2009 g_object_set_data( tbl, "item", item );
2010 Inkscape::GC::anchor(repr);
2011 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
2012 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
2013 }
2014 } else {
2015 // FIXME: implement averaging of all parameters for multiple selected
2016 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2017 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2018 sp_rtb_sensitivize( tbl );
2019 }
2020 }
2023 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2024 {
2025 EgeAdjustmentAction* eact = 0;
2027 {
2028 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2029 ege_output_action_set_use_markup( act, TRUE );
2030 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2031 g_object_set_data( holder, "mode_action", act );
2032 }
2034 // rx/ry units menu: create
2035 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2036 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2037 // fixme: add % meaning per cent of the width/height
2038 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2039 g_object_set_data( holder, "tracker", tracker );
2041 /* W */
2042 {
2043 eact = create_adjustment_action( "RectWidthAction",
2044 _("W:"), _("Width of rectangle"),
2045 "tools.shapes.rect", "width", 0,
2046 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2047 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2048 0, 0, 0,
2049 sp_rtb_width_value_changed );
2050 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2051 g_object_set_data( holder, "width_action", eact );
2052 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2053 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2054 }
2056 /* H */
2057 {
2058 eact = create_adjustment_action( "RectHeightAction",
2059 _("H:"), _("Height of rectangle"),
2060 "tools.shapes.rect", "height", 0,
2061 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2062 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2063 0, 0, 0,
2064 sp_rtb_height_value_changed );
2065 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2066 g_object_set_data( holder, "height_action", eact );
2067 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2068 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2069 }
2071 /* rx */
2072 {
2073 eact = create_adjustment_action( "RadiusXAction",
2074 _("Rx:"), _("Horizontal radius of rounded corners"),
2075 "tools.shapes.rect", "rx", 0,
2076 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2077 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2078 0, 0, 0,
2079 sp_rtb_rx_value_changed);
2080 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2081 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2082 }
2084 /* ry */
2085 {
2086 eact = create_adjustment_action( "RadiusYAction",
2087 _("Ry:"), _("Vertical radius of rounded corners"),
2088 "tools.shapes.rect", "ry", 0,
2089 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2090 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2091 0, 0, 0,
2092 sp_rtb_ry_value_changed);
2093 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2094 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2095 }
2097 // add the units menu
2098 {
2099 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), _("") );
2100 gtk_action_group_add_action( mainActions, act );
2101 }
2103 /* Reset */
2104 {
2105 InkAction* inky = ink_action_new( "RectResetAction",
2106 _("Not rounded"),
2107 _("Make corners sharp"),
2108 "squared_corner",
2109 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2110 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2111 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2112 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2113 g_object_set_data( holder, "not_rounded", inky );
2114 }
2116 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2117 sp_rtb_sensitivize( holder );
2119 sigc::connection *connection = new sigc::connection(
2120 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2121 );
2122 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2123 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2124 }
2126 //########################
2127 //## 3D Box ##
2128 //########################
2130 static void sp_3dbox_toggle_vp_changed( GtkToggleAction *act, gpointer data )
2131 {
2132 SPDocument *document = sp_desktop_document (inkscape_active_desktop ());
2133 Box3D::Axis axis = (Box3D::Axis) GPOINTER_TO_INT(data);
2135 if (document->current_perspective) {
2136 document->current_perspective->toggle_boxes (axis);
2137 }
2139 }
2141 static void sp_3dboxtb_handles_state_changed( EgeSelectOneAction *act, GObject *tbl )
2142 {
2143 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2144 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2145 if ( ege_select_one_action_get_active( act ) != 0 ) {
2146 prefs_set_string_attribute("tools.shapes.3dbox", "constrainedXYmoving", "true");
2147 } else {
2148 prefs_set_string_attribute("tools.shapes.3dbox", "constrainedXYmoving", "false");
2149 }
2150 }
2152 // quit if run by the attr_changed listener
2153 if (g_object_get_data( tbl, "freeze" )) {
2154 return;
2155 }
2157 // in turn, prevent listener from responding
2158 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2160 bool modmade = false;
2162 SPEventContext *ec = SP_EVENT_CONTEXT(inkscape_active_event_context());
2163 if (!SP_IS_3DBOX_CONTEXT(ec)) return;
2164 SP3DBoxContext *bc = SP_3DBOX_CONTEXT(ec);
2165 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2166 items != NULL;
2167 items = items->next)
2168 {
2169 if (SP_IS_3DBOX((SPItem *) items->data)) {
2170 if (ec->shape_knot_holder) {
2171 sp_knot_holder_destroy(ec->shape_knot_holder);
2172 if ( ege_select_one_action_get_active(act) != 0 ) {
2173 bc->number_of_handles = 4;
2174 ec->shape_knot_holder = sp_3dbox_knot_holder((SPItem *) items->data, SP_ACTIVE_DESKTOP, 4);;
2175 } else {
2176 bc->number_of_handles = 3;
2177 ec->shape_knot_holder = sp_3dbox_knot_holder((SPItem *) items->data, SP_ACTIVE_DESKTOP, 3);;
2178 }
2179 } else {
2180 g_print ("Warning: No KnotHolder detected!!!\n");
2181 }
2182 modmade = true;
2183 }
2184 }
2186 if (modmade) {
2187 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
2188 _("3D Box: Change number of handles"));
2189 }
2191 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2192 }
2195 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2196 {
2197 SPDocument *document = sp_desktop_document (desktop);
2198 bool toggled = false;
2199 /* toggle VP in X direction */
2200 {
2201 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXAction",
2202 _("Toggle VP in X direction"),
2203 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2204 "toggle_vp_x",
2205 Inkscape::ICON_SIZE_DECORATION );
2206 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2207 if (document->current_perspective) {
2208 toggled = !document->current_perspective->get_vanishing_point(Box3D::X)->is_finite();
2209 }
2210 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
2211 /* we connect the signal after setting the state to avoid switching the state again */
2212 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), GINT_TO_POINTER(Box3D::X));
2213 }
2215 /* toggle VP in Y direction */
2216 {
2217 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYAction",
2218 _("Toggle VP in Y direction"),
2219 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2220 "toggle_vp_y",
2221 Inkscape::ICON_SIZE_DECORATION );
2222 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2223 if (document->current_perspective) {
2224 toggled = !document->current_perspective->get_vanishing_point(Box3D::Y)->is_finite();
2225 }
2226 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
2227 /* we connect the signal after setting the state to avoid switching the state again */
2228 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), GINT_TO_POINTER(Box3D::Y));
2229 }
2231 /* toggle VP in Z direction */
2232 {
2233 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZAction",
2234 _("Toggle VP in Z direction"),
2235 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
2236 "toggle_vp_z",
2237 Inkscape::ICON_SIZE_DECORATION );
2238 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2239 if (document->current_perspective) {
2240 toggled = !document->current_perspective->get_vanishing_point(Box3D::Z)->is_finite();
2241 }
2242 /* we connect the signal after setting the state to avoid switching the state again */
2243 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
2244 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), GINT_TO_POINTER(Box3D::Z));
2245 }
2248 /* Number of handles and resizing behaviour */
2249 {
2250 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2252 GtkTreeIter iter;
2253 gtk_list_store_append( model, &iter );
2254 gtk_list_store_set( model, &iter,
2255 0, _("Three Handles"),
2256 1, _("Switch to three handles (arbitrary resizing in XY-direction)"),
2257 2, "3dbox_three_handles",
2258 -1 );
2260 gtk_list_store_append( model, &iter );
2261 gtk_list_store_set( model, &iter,
2262 0, _("Four Handles"),
2263 1, _("Switch to four handles (constrained resizing in XY-direction)"),
2264 2, "3dbox_four_handles",
2265 -1 );
2267 EgeSelectOneAction* act = ege_select_one_action_new( "3DBoxHandlesAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
2268 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2269 g_object_set_data( holder, "handles_action", act );
2271 ege_select_one_action_set_appearance( act, "full" );
2272 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2273 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2274 ege_select_one_action_set_icon_column( act, 2 );
2275 ege_select_one_action_set_tooltip_column( act, 1 );
2277 gchar const *handlestr = prefs_get_string_attribute("tools.shapes.3dbox", "constrainedXYmoving");
2278 bool isConstrained = (!handlestr || (handlestr && !strcmp(handlestr, "true")));
2279 ege_select_one_action_set_active( act, isConstrained ? 0 : 1 );
2280 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_3dboxtb_handles_state_changed), holder );
2281 }
2282 }
2284 //########################
2285 //## Spiral ##
2286 //########################
2288 static void
2289 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2290 {
2291 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2293 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2294 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2295 }
2297 // quit if run by the attr_changed listener
2298 if (g_object_get_data( tbl, "freeze" )) {
2299 return;
2300 }
2302 // in turn, prevent listener from responding
2303 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2305 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2307 bool modmade = false;
2308 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2309 items != NULL;
2310 items = items->next)
2311 {
2312 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2313 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2314 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2315 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2316 modmade = true;
2317 }
2318 }
2320 g_free(namespaced_name);
2322 if (modmade) {
2323 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2324 _("Change spiral"));
2325 }
2327 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2328 }
2330 static void
2331 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2332 {
2333 sp_spl_tb_value_changed(adj, tbl, "revolution");
2334 }
2336 static void
2337 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2338 {
2339 sp_spl_tb_value_changed(adj, tbl, "expansion");
2340 }
2342 static void
2343 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2344 {
2345 sp_spl_tb_value_changed(adj, tbl, "t0");
2346 }
2348 static void
2349 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
2350 {
2351 GtkWidget *tbl = GTK_WIDGET(obj);
2353 GtkAdjustment *adj;
2355 // fixme: make settable
2356 gdouble rev = 5;
2357 gdouble exp = 1.0;
2358 gdouble t0 = 0.0;
2360 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2361 gtk_adjustment_set_value(adj, rev);
2362 gtk_adjustment_value_changed(adj);
2364 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2365 gtk_adjustment_set_value(adj, exp);
2366 gtk_adjustment_value_changed(adj);
2368 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2369 gtk_adjustment_set_value(adj, t0);
2370 gtk_adjustment_value_changed(adj);
2372 spinbutton_defocus(GTK_OBJECT(tbl));
2373 }
2376 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2377 gchar const *old_value, gchar const *new_value,
2378 bool is_interactive, gpointer data)
2379 {
2380 GtkWidget *tbl = GTK_WIDGET(data);
2382 // quit if run by the _changed callbacks
2383 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2384 return;
2385 }
2387 // in turn, prevent callbacks from responding
2388 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2390 GtkAdjustment *adj;
2391 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2392 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2394 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2395 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2397 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2398 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2400 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2401 }
2404 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2405 NULL, /* child_added */
2406 NULL, /* child_removed */
2407 spiral_tb_event_attr_changed,
2408 NULL, /* content_changed */
2409 NULL /* order_changed */
2410 };
2412 static void
2413 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2414 {
2415 int n_selected = 0;
2416 Inkscape::XML::Node *repr = NULL;
2418 purge_repr_listener( tbl, tbl );
2420 for (GSList const *items = selection->itemList();
2421 items != NULL;
2422 items = items->next)
2423 {
2424 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2425 n_selected++;
2426 repr = SP_OBJECT_REPR((SPItem *) items->data);
2427 }
2428 }
2430 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2432 if (n_selected == 0) {
2433 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2434 } else if (n_selected == 1) {
2435 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2437 if (repr) {
2438 g_object_set_data( tbl, "repr", repr );
2439 Inkscape::GC::anchor(repr);
2440 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2441 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2442 }
2443 } else {
2444 // FIXME: implement averaging of all parameters for multiple selected
2445 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2446 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2447 }
2448 }
2451 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2452 {
2453 EgeAdjustmentAction* eact = 0;
2455 {
2456 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2457 ege_output_action_set_use_markup( act, TRUE );
2458 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2459 g_object_set_data( holder, "mode_action", act );
2460 }
2462 /* Revolution */
2463 {
2464 eact = create_adjustment_action( "SpiralRevolutionAction",
2465 _("Turns:"), _("Number of revolutions"),
2466 "tools.shapes.spiral", "revolution", 3.0,
2467 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2468 0.01, 1024.0, 0.1, 1.0,
2469 0, 0, 0,
2470 sp_spl_tb_revolution_value_changed, 1, 2);
2471 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2472 }
2474 /* Expansion */
2475 {
2476 eact = create_adjustment_action( "SpiralExpansionAction",
2477 _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2478 "tools.shapes.spiral", "expansion", 1.0,
2479 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2480 0.0, 1000.0, 0.01, 1.0,
2481 0, 0, 0,
2482 sp_spl_tb_expansion_value_changed);
2483 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2484 }
2486 /* T0 */
2487 {
2488 eact = create_adjustment_action( "SpiralT0Action",
2489 _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2490 "tools.shapes.spiral", "t0", 0.0,
2491 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2492 0.0, 0.999, 0.01, 1.0,
2493 0, 0, 0,
2494 sp_spl_tb_t0_value_changed);
2495 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2496 }
2498 /* Reset */
2499 {
2500 InkAction* inky = ink_action_new( "SpiralResetAction",
2501 _("Defaults"),
2502 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2503 GTK_STOCK_CLEAR,
2504 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2505 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2506 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2507 }
2510 sigc::connection *connection = new sigc::connection(
2511 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2512 );
2513 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2514 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2515 }
2517 //########################
2518 //## Pen/Pencil ##
2519 //########################
2522 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2523 {
2524 // Put stuff here
2525 }
2527 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2528 {
2529 // Put stuff here
2530 }
2532 //########################
2533 //## Tweak ##
2534 //########################
2536 static void sp_tweak_width_value_changed( GtkAdjustment *adj, GObject *tbl )
2537 {
2538 prefs_set_double_attribute( "tools.tweak", "width", adj->value * 0.01 );
2539 }
2541 static void sp_tweak_force_value_changed( GtkAdjustment *adj, GObject *tbl )
2542 {
2543 prefs_set_double_attribute( "tools.tweak", "force", adj->value * 0.01 );
2544 }
2546 static void sp_tweak_pressure_state_changed( GtkToggleAction *act, gpointer data )
2547 {
2548 prefs_set_int_attribute( "tools.tweak", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2549 }
2551 static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
2552 {
2553 prefs_set_int_attribute("tools.tweak", "mode", ege_select_one_action_get_active( act ));
2554 }
2556 static void sp_tweak_fidelity_value_changed( GtkAdjustment *adj, GObject *tbl )
2557 {
2558 prefs_set_double_attribute( "tools.tweak", "fidelity", adj->value * 0.01 );
2559 }
2562 static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2563 {
2564 {
2565 /* Width */
2566 gchar const* labels[] = {_("(pinch tweak)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad tweak)")};
2567 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2568 EgeAdjustmentAction *eact = create_adjustment_action( "TweakWidthAction",
2569 _("Width:"), _("The width of the tweak area (relative to the visible canvas area)"),
2570 "tools.tweak", "width", 15,
2571 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-tweak",
2572 1, 100, 1.0, 10.0,
2573 labels, values, G_N_ELEMENTS(labels),
2574 sp_tweak_width_value_changed, 0.01, 0, 100 );
2575 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2576 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2577 }
2580 {
2581 /* Force */
2582 gchar const* labels[] = {_("(minimum force)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum force)")};
2583 gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100};
2584 EgeAdjustmentAction *eact = create_adjustment_action( "TweakForceAction",
2585 _("Force:"), _("The force of the tweak action"),
2586 "tools.tweak", "force", 20,
2587 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-force",
2588 1, 100, 1.0, 10.0,
2589 labels, values, G_N_ELEMENTS(labels),
2590 sp_tweak_force_value_changed, 0.01, 0, 100 );
2591 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2592 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2593 }
2595 /* Mode */
2596 {
2597 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2599 GtkTreeIter iter;
2600 gtk_list_store_append( model, &iter );
2601 gtk_list_store_set( model, &iter,
2602 0, _("Push mode"),
2603 1, _("Switch to Push mode"),
2604 2, "tweak_push_mode",
2605 -1 );
2607 gtk_list_store_append( model, &iter );
2608 gtk_list_store_set( model, &iter,
2609 0, _("Melt mode"),
2610 1, _("Switch to Melt mode"),
2611 2, "tweak_suck_mode",
2612 -1 );
2614 gtk_list_store_append( model, &iter );
2615 gtk_list_store_set( model, &iter,
2616 0, _("Blow mode"),
2617 1, _("Switch to Blow mode"),
2618 2, "tweak_blow_mode",
2619 -1 );
2621 gtk_list_store_append( model, &iter );
2622 gtk_list_store_set( model, &iter,
2623 0, _("Roughen mode"),
2624 1, _("Switch to Roughen mode"),
2625 2, "tweak_roughen_mode",
2626 -1 );
2628 EgeSelectOneAction* act = ege_select_one_action_new( "TweakModeAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
2629 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2630 g_object_set_data( holder, "mode_action", act );
2632 ege_select_one_action_set_appearance( act, "full" );
2633 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2634 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2635 ege_select_one_action_set_icon_column( act, 2 );
2636 ege_select_one_action_set_tooltip_column( act, 1 );
2638 gint mode = prefs_get_int_attribute("tools.tweak", "mode", 0);
2639 ege_select_one_action_set_active( act, mode );
2640 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_tweak_mode_changed), holder );
2642 g_object_set_data( G_OBJECT(holder), "tweak_tool_mode", act);
2643 }
2645 { /* Fidelity */
2646 gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")};
2647 gdouble values[] = {10, 25, 35, 50, 60, 80, 100};
2648 EgeAdjustmentAction *eact = create_adjustment_action( "TweakFidelityAction",
2649 _("Fidelity:"), _("Low fidelity simplifies paths; high fidelity preserves path features but may generate a lot of new nodes"),
2650 "tools.tweak", "fidelity", 50,
2651 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "tweak-fidelity",
2652 1, 100, 1.0, 10.0,
2653 labels, values, G_N_ELEMENTS(labels),
2654 sp_tweak_fidelity_value_changed, 0.01, 0, 100 );
2655 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2656 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2657 }
2660 /* Use Pressure button */
2661 {
2662 InkToggleAction* act = ink_toggle_action_new( "TweakPressureAction",
2663 _("Pressure"),
2664 _("Use the pressure of the input device to alter the width of the area"),
2665 "use_pressure",
2666 Inkscape::ICON_SIZE_DECORATION );
2667 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2668 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_tweak_pressure_state_changed), NULL);
2669 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.tweak", "usepressure", 1 ) );
2670 }
2672 }
2675 //########################
2676 //## Calligraphy ##
2677 //########################
2679 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
2680 {
2681 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
2682 }
2684 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
2685 {
2686 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
2687 }
2689 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
2690 {
2691 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
2692 }
2694 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
2695 {
2696 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
2697 }
2699 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
2700 {
2701 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
2702 }
2704 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
2705 {
2706 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
2707 }
2709 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
2710 {
2711 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
2712 }
2714 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
2715 {
2716 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
2717 }
2719 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer data )
2720 {
2721 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2722 }
2724 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer data )
2725 {
2726 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
2727 }
2729 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
2730 {
2731 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2733 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
2734 }
2736 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
2737 {
2738 // FIXME: make defaults settable via Inkscape Options
2739 struct KeyValue {
2740 char const *key;
2741 double value;
2742 } const key_values[] = {
2743 {"mass", 0.02},
2744 {"wiggle", 0.0},
2745 {"angle", 30.0},
2746 {"width", 15},
2747 {"thinning", 0.1},
2748 {"tremor", 0.0},
2749 {"flatness", 0.9},
2750 {"cap_rounding", 0.0}
2751 };
2753 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2754 KeyValue const &kv = key_values[i];
2755 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
2756 if ( adj ) {
2757 gtk_adjustment_set_value(adj, kv.value);
2758 }
2759 }
2760 }
2763 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2764 {
2765 {
2766 EgeAdjustmentAction* calligraphy_angle = 0;
2768 {
2769 /* Width */
2770 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
2771 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2772 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
2773 _("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2774 "tools.calligraphic", "width", 15,
2775 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
2776 1, 100, 1.0, 10.0,
2777 labels, values, G_N_ELEMENTS(labels),
2778 sp_ddc_width_value_changed, 0.01, 0, 100 );
2779 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2780 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2781 }
2783 {
2784 /* Thinning */
2785 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
2786 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
2787 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
2788 _("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2789 "tools.calligraphic", "thinning", 0.1,
2790 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2791 -1.0, 1.0, 0.01, 0.1,
2792 labels, values, G_N_ELEMENTS(labels),
2793 sp_ddc_velthin_value_changed, 0.01, 2);
2794 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2795 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2796 }
2798 {
2799 /* Angle */
2800 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
2801 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2802 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
2803 _("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2804 "tools.calligraphic", "angle", 30,
2805 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
2806 -90.0, 90.0, 1.0, 10.0,
2807 labels, values, G_N_ELEMENTS(labels),
2808 sp_ddc_angle_value_changed, 1, 0 );
2809 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2810 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2811 calligraphy_angle = eact;
2812 }
2814 {
2815 /* Fixation */
2816 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
2817 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
2818 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
2819 _("Fixation:"), _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
2820 "tools.calligraphic", "flatness", 0.9,
2821 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2822 0.0, 1.0, 0.01, 0.1,
2823 labels, values, G_N_ELEMENTS(labels),
2824 sp_ddc_flatness_value_changed, 0.01, 2 );
2825 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2826 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2827 }
2829 {
2830 /* Cap Rounding */
2831 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
2832 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
2833 // TRANSLATORS: "cap" means "end" (both start and finish) here
2834 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
2835 _("Caps:"), _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
2836 "tools.calligraphic", "cap_rounding", 0.0,
2837 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2838 0.0, 5.0, 0.01, 0.1,
2839 labels, values, G_N_ELEMENTS(labels),
2840 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
2841 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2842 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2843 }
2845 {
2846 /* Tremor */
2847 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
2848 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
2849 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
2850 _("Tremor:"), _("Increase to make strokes rugged and trembling"),
2851 "tools.calligraphic", "tremor", 0.0,
2852 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2853 0.0, 1.0, 0.01, 0.1,
2854 labels, values, G_N_ELEMENTS(labels),
2855 sp_ddc_tremor_value_changed, 0.01, 2 );
2857 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2858 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2859 }
2861 {
2862 /* Wiggle */
2863 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
2864 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
2865 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
2866 _("Wiggle:"), _("Increase to make the pen waver and wiggle"),
2867 "tools.calligraphic", "wiggle", 0.0,
2868 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2869 0.0, 1.0, 0.01, 0.1,
2870 labels, values, G_N_ELEMENTS(labels),
2871 sp_ddc_wiggle_value_changed, 0.01, 2 );
2872 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2873 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2874 }
2876 {
2877 /* Mass */
2878 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
2879 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
2880 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
2881 _("Mass:"), _("Increase to make the pen drag behind, as if slowed by inertia"),
2882 "tools.calligraphic", "mass", 0.02,
2883 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2884 0.0, 1.0, 0.01, 0.1,
2885 labels, values, G_N_ELEMENTS(labels),
2886 sp_ddc_mass_value_changed, 0.01, 2 );
2887 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2888 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2889 }
2892 /* Trace Background button */
2893 {
2894 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
2895 _("Trace Background"),
2896 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
2897 "trace_background",
2898 Inkscape::ICON_SIZE_DECORATION );
2899 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2900 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
2901 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
2902 }
2904 /* Use Pressure button */
2905 {
2906 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
2907 _("Pressure"),
2908 _("Use the pressure of the input device to alter the width of the pen"),
2909 "use_pressure",
2910 Inkscape::ICON_SIZE_DECORATION );
2911 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2912 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
2913 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
2914 }
2916 /* Use Tilt button */
2917 {
2918 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
2919 _("Tilt"),
2920 _("Use the tilt of the input device to alter the angle of the pen's nib"),
2921 "use_tilt",
2922 Inkscape::ICON_SIZE_DECORATION );
2923 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2924 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
2925 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2926 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2927 }
2929 /* Reset */
2930 {
2931 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
2932 _("Defaults"),
2933 _("Reset all parameters to defaults"),
2934 GTK_STOCK_CLEAR );
2935 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
2936 gtk_action_group_add_action( mainActions, act );
2937 gtk_action_set_sensitive( act, TRUE );
2938 }
2939 }
2940 }
2943 //########################
2944 //## Circle / Arc ##
2945 //########################
2947 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
2948 {
2949 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
2950 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
2952 if (v1 == 0 && v2 == 0) {
2953 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
2954 gtk_action_set_sensitive( ocb, FALSE );
2955 gtk_action_set_sensitive( make_whole, FALSE );
2956 }
2957 } else {
2958 gtk_action_set_sensitive( ocb, TRUE );
2959 gtk_action_set_sensitive( make_whole, TRUE );
2960 }
2961 }
2963 static void
2964 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
2965 {
2966 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2968 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2969 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2970 }
2972 // quit if run by the attr_changed listener
2973 if (g_object_get_data( tbl, "freeze" )) {
2974 return;
2975 }
2977 // in turn, prevent listener from responding
2978 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2980 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2982 bool modmade = false;
2983 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2984 items != NULL;
2985 items = items->next)
2986 {
2987 SPItem *item = SP_ITEM(items->data);
2989 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2991 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2992 SPArc *arc = SP_ARC(item);
2994 if (!strcmp(value_name, "start"))
2995 ge->start = (adj->value * M_PI)/ 180;
2996 else
2997 ge->end = (adj->value * M_PI)/ 180;
2999 sp_genericellipse_normalize(ge);
3000 ((SPObject *)arc)->updateRepr();
3001 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
3003 modmade = true;
3004 }
3005 }
3007 g_free(namespaced_name);
3009 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
3011 sp_arctb_sensitivize( tbl, adj->value, other->value );
3013 if (modmade) {
3014 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
3015 _("Arc: Change start/end"));
3016 }
3018 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3019 }
3022 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
3023 {
3024 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
3025 }
3027 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
3028 {
3029 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
3030 }
3032 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
3033 {
3034 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
3035 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
3036 if ( ege_select_one_action_get_active( act ) != 0 ) {
3037 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
3038 } else {
3039 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
3040 }
3041 }
3043 // quit if run by the attr_changed listener
3044 if (g_object_get_data( tbl, "freeze" )) {
3045 return;
3046 }
3048 // in turn, prevent listener from responding
3049 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3051 bool modmade = false;
3053 if ( ege_select_one_action_get_active(act) != 0 ) {
3054 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3055 items != NULL;
3056 items = items->next)
3057 {
3058 if (SP_IS_ARC((SPItem *) items->data)) {
3059 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3060 repr->setAttribute("sodipodi:open", "true");
3061 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3062 modmade = true;
3063 }
3064 }
3065 } else {
3066 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
3067 items != NULL;
3068 items = items->next)
3069 {
3070 if (SP_IS_ARC((SPItem *) items->data)) {
3071 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
3072 repr->setAttribute("sodipodi:open", NULL);
3073 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
3074 modmade = true;
3075 }
3076 }
3077 }
3079 if (modmade) {
3080 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
3081 _("Arc: Change open/closed"));
3082 }
3084 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3085 }
3087 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
3088 {
3089 GtkAdjustment *adj;
3090 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
3091 gtk_adjustment_set_value(adj, 0.0);
3092 gtk_adjustment_value_changed(adj);
3094 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
3095 gtk_adjustment_set_value(adj, 0.0);
3096 gtk_adjustment_value_changed(adj);
3098 spinbutton_defocus( GTK_OBJECT(obj) );
3099 }
3101 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
3102 gchar const *old_value, gchar const *new_value,
3103 bool is_interactive, gpointer data)
3104 {
3105 GObject *tbl = G_OBJECT(data);
3107 // quit if run by the _changed callbacks
3108 if (g_object_get_data( tbl, "freeze" )) {
3109 return;
3110 }
3112 // in turn, prevent callbacks from responding
3113 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
3115 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
3116 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
3118 GtkAdjustment *adj1,*adj2;
3119 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
3120 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
3121 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
3122 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
3124 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
3126 char const *openstr = NULL;
3127 openstr = repr->attribute("sodipodi:open");
3128 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
3130 if (openstr) {
3131 ege_select_one_action_set_active( ocb, 1 );
3132 } else {
3133 ege_select_one_action_set_active( ocb, 0 );
3134 }
3136 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
3137 }
3139 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
3140 NULL, /* child_added */
3141 NULL, /* child_removed */
3142 arc_tb_event_attr_changed,
3143 NULL, /* content_changed */
3144 NULL /* order_changed */
3145 };
3148 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
3149 {
3150 int n_selected = 0;
3151 Inkscape::XML::Node *repr = NULL;
3153 purge_repr_listener( tbl, tbl );
3155 for (GSList const *items = selection->itemList();
3156 items != NULL;
3157 items = items->next)
3158 {
3159 if (SP_IS_ARC((SPItem *) items->data)) {
3160 n_selected++;
3161 repr = SP_OBJECT_REPR((SPItem *) items->data);
3162 }
3163 }
3165 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
3167 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
3168 if (n_selected == 0) {
3169 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
3170 } else if (n_selected == 1) {
3171 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
3172 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3174 if (repr) {
3175 g_object_set_data( tbl, "repr", repr );
3176 Inkscape::GC::anchor(repr);
3177 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
3178 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
3179 }
3180 } else {
3181 // FIXME: implement averaging of all parameters for multiple selected
3182 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
3183 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
3184 sp_arctb_sensitivize( tbl, 1, 0 );
3185 }
3186 }
3189 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3190 {
3191 EgeAdjustmentAction* eact = 0;
3194 {
3195 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
3196 ege_output_action_set_use_markup( act, TRUE );
3197 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3198 g_object_set_data( holder, "mode_action", act );
3199 }
3201 /* Start */
3202 {
3203 eact = create_adjustment_action( "ArcStartAction",
3204 _("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
3205 "tools.shapes.arc", "start", 0.0,
3206 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
3207 -360.0, 360.0, 1.0, 10.0,
3208 0, 0, 0,
3209 sp_arctb_start_value_changed);
3210 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3211 }
3213 /* End */
3214 {
3215 eact = create_adjustment_action( "ArcEndAction",
3216 _("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
3217 "tools.shapes.arc", "end", 0.0,
3218 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
3219 -360.0, 360.0, 1.0, 10.0,
3220 0, 0, 0,
3221 sp_arctb_end_value_changed);
3222 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
3223 }
3225 /* Segments / Pie checkbox */
3226 {
3227 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
3229 GtkTreeIter iter;
3230 gtk_list_store_append( model, &iter );
3231 gtk_list_store_set( model, &iter,
3232 0, _("Closed arc"),
3233 1, _("Switch to segment (closed shape with two radii)"),
3234 2, "circle_closed_arc",
3235 -1 );
3237 gtk_list_store_append( model, &iter );
3238 gtk_list_store_set( model, &iter,
3239 0, _("Open Arc"),
3240 1, _("Switch to arc (unclosed shape)"),
3241 2, "circle_open_arc",
3242 -1 );
3244 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
3245 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3246 g_object_set_data( holder, "open_action", act );
3248 ege_select_one_action_set_appearance( act, "full" );
3249 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3250 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3251 ege_select_one_action_set_icon_column( act, 2 );
3252 ege_select_one_action_set_tooltip_column( act, 1 );
3254 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
3255 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
3256 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
3257 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
3258 }
3260 /* Make Whole */
3261 {
3262 InkAction* inky = ink_action_new( "ArcResetAction",
3263 _("Make whole"),
3264 _("Make the shape a whole ellipse, not arc or segment"),
3265 "reset_circle",
3266 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3267 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
3268 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3269 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3270 g_object_set_data( holder, "make_whole", inky );
3271 }
3273 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
3274 // sensitivize make whole and open checkbox
3275 {
3276 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
3277 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
3278 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
3279 }
3282 sigc::connection *connection = new sigc::connection(
3283 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
3284 );
3285 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3286 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3287 }
3292 // toggle button callbacks and updaters
3294 //########################
3295 //## Dropper ##
3296 //########################
3298 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
3299 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
3300 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
3301 if ( set_action ) {
3302 if ( gtk_toggle_action_get_active( act ) ) {
3303 gtk_action_set_sensitive( set_action, TRUE );
3304 } else {
3305 gtk_action_set_sensitive( set_action, FALSE );
3306 }
3307 }
3309 spinbutton_defocus(GTK_OBJECT(tbl));
3310 }
3312 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
3313 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3314 spinbutton_defocus(GTK_OBJECT(tbl));
3315 }
3318 /**
3319 * Dropper auxiliary toolbar construction and setup.
3320 *
3321 * TODO: Would like to add swatch of current color.
3322 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3323 * can drag and drop places. Will provide a nice mixing palette.
3324 */
3325 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3326 {
3327 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
3329 {
3330 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
3331 _("Pick alpha"),
3332 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
3333 "color_alpha_get",
3334 Inkscape::ICON_SIZE_DECORATION );
3335 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3336 g_object_set_data( holder, "pick_action", act );
3337 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
3338 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
3339 }
3341 {
3342 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
3343 _("Set alpha"),
3344 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
3345 "color_alpha_set",
3346 Inkscape::ICON_SIZE_DECORATION );
3347 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3348 g_object_set_data( holder, "set_action", act );
3349 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
3350 // make sure it's disabled if we're not picking alpha
3351 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
3352 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
3353 }
3354 }
3357 //########################
3358 //## Text Toolbox ##
3359 //########################
3360 /*
3361 static void
3362 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3363 {
3364 //Call back for letter sizing spinbutton
3365 }
3367 static void
3368 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3369 {
3370 //Call back for line height spinbutton
3371 }
3373 static void
3374 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3375 {
3376 //Call back for horizontal kerning spinbutton
3377 }
3379 static void
3380 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3381 {
3382 //Call back for vertical kerning spinbutton
3383 }
3385 static void
3386 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3387 {
3388 //Call back for letter rotation spinbutton
3389 }*/
3391 namespace {
3393 bool visible = false;
3395 void
3396 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
3397 {
3398 SPStyle *query =
3399 sp_style_new (SP_ACTIVE_DOCUMENT);
3401 int result_family =
3402 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3404 int result_style =
3405 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3407 int result_numbers =
3408 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3410 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3412 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3413 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3414 {
3415 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3417 if (repr)
3418 {
3419 sp_style_read_from_repr (query, repr);
3420 }
3421 else
3422 {
3423 return;
3424 }
3425 }
3427 if (query->text)
3428 {
3429 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3430 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3431 gtk_entry_set_text (GTK_ENTRY (entry), "");
3433 } else if (query->text->font_family.value) {
3435 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3436 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3438 Gtk::TreePath path;
3439 try {
3440 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3441 } catch (...) {
3442 return;
3443 }
3445 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3446 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3448 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3450 gtk_tree_selection_select_path (tselection, path.gobj());
3451 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3453 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3454 }
3456 //Size
3457 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3458 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3459 g_object_set_data (tbl, "size-block", gpointer(1));
3460 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3461 g_object_set_data (tbl, "size-block", gpointer(0));
3462 free (str);
3464 //Anchor
3465 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3466 {
3467 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3468 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3469 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3470 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3471 }
3472 else
3473 {
3474 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3475 {
3476 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3477 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3478 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3479 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3480 }
3481 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3482 {
3483 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3484 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3485 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3486 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3487 }
3488 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3489 {
3490 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3491 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3492 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3493 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3494 }
3495 }
3497 //Style
3498 {
3499 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3501 gboolean active = gtk_toggle_button_get_active (button);
3502 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3504 if (active != check)
3505 {
3506 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3507 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3508 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3509 }
3510 }
3512 {
3513 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3515 gboolean active = gtk_toggle_button_get_active (button);
3516 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3518 if (active != check)
3519 {
3520 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3521 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3522 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3523 }
3524 }
3526 //Orientation
3527 //locking both buttons, changing one affect all group (both)
3528 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3529 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3531 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3532 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3534 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3535 {
3536 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3537 }
3538 else
3539 {
3540 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3541 }
3542 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3543 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3544 }
3546 sp_style_unref(query);
3547 }
3549 void
3550 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
3551 {
3552 sp_text_toolbox_selection_changed (selection, tbl);
3553 }
3555 void
3556 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3557 {
3558 sp_text_toolbox_selection_changed (NULL, tbl);
3559 }
3561 void
3562 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
3563 GObject *tbl)
3564 {
3565 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3566 GtkTreeModel *model = 0;
3567 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3568 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3569 GtkTreeIter iter;
3570 char *family = 0;
3572 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3573 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3575 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3576 return;
3577 }
3579 gtk_tree_model_get (model, &iter, 0, &family, -1);
3581 if (g_object_get_data (G_OBJECT (selection), "block"))
3582 {
3583 gtk_entry_set_text (GTK_ENTRY (entry), family);
3584 return;
3585 }
3587 gtk_widget_hide (popdown);
3588 visible = false;
3590 gtk_entry_set_text (GTK_ENTRY (entry), family);
3592 SPStyle *query =
3593 sp_style_new (SP_ACTIVE_DOCUMENT);
3595 int result_numbers =
3596 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3598 SPCSSAttr *css = sp_repr_css_attr_new ();
3599 sp_repr_css_set_property (css, "font-family", family);
3601 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3602 if (result_numbers == QUERY_STYLE_NOTHING)
3603 {
3604 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3605 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3606 }
3607 else
3608 {
3609 sp_desktop_set_style (desktop, css, true, true);
3610 }
3612 sp_style_unref(query);
3614 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3615 _("Text: Change font family"));
3616 sp_repr_css_attr_unref (css);
3617 free (family);
3618 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3620 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3621 }
3623 void
3624 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
3625 GObject *tbl)
3626 {
3627 const char *family = gtk_entry_get_text (entry);
3629 try {
3630 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3631 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3632 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3633 gtk_tree_selection_select_path (selection, path.gobj());
3634 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3635 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3636 } catch (...) {
3637 if (family && strlen (family))
3638 {
3639 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3640 }
3641 }
3642 }
3644 void
3645 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
3646 gpointer data)
3647 {
3648 if (g_object_get_data (G_OBJECT (button), "block")) return;
3649 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3650 int prop = GPOINTER_TO_INT(data);
3652 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3653 SPCSSAttr *css = sp_repr_css_attr_new ();
3655 switch (prop)
3656 {
3657 case 0:
3658 {
3659 sp_repr_css_set_property (css, "text-anchor", "start");
3660 sp_repr_css_set_property (css, "text-align", "start");
3661 break;
3662 }
3663 case 1:
3664 {
3665 sp_repr_css_set_property (css, "text-anchor", "middle");
3666 sp_repr_css_set_property (css, "text-align", "center");
3667 break;
3668 }
3670 case 2:
3671 {
3672 sp_repr_css_set_property (css, "text-anchor", "end");
3673 sp_repr_css_set_property (css, "text-align", "end");
3674 break;
3675 }
3677 case 3:
3678 {
3679 sp_repr_css_set_property (css, "text-anchor", "start");
3680 sp_repr_css_set_property (css, "text-align", "justify");
3681 break;
3682 }
3683 }
3685 SPStyle *query =
3686 sp_style_new (SP_ACTIVE_DOCUMENT);
3687 int result_numbers =
3688 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3690 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3691 if (result_numbers == QUERY_STYLE_NOTHING)
3692 {
3693 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3694 }
3696 sp_style_unref(query);
3698 sp_desktop_set_style (desktop, css, true, true);
3699 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3700 _("Text: Change alignment"));
3701 sp_repr_css_attr_unref (css);
3703 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3704 }
3706 void
3707 sp_text_toolbox_style_toggled (GtkToggleButton *button,
3708 gpointer data)
3709 {
3710 if (g_object_get_data (G_OBJECT (button), "block")) return;
3712 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3713 SPCSSAttr *css = sp_repr_css_attr_new ();
3714 int prop = GPOINTER_TO_INT(data);
3715 bool active = gtk_toggle_button_get_active (button);
3718 switch (prop)
3719 {
3720 case 0:
3721 {
3722 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
3723 break;
3724 }
3726 case 1:
3727 {
3728 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
3729 break;
3730 }
3731 }
3733 SPStyle *query =
3734 sp_style_new (SP_ACTIVE_DOCUMENT);
3735 int result_numbers =
3736 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3738 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3739 if (result_numbers == QUERY_STYLE_NOTHING)
3740 {
3741 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3742 }
3744 sp_style_unref(query);
3746 sp_desktop_set_style (desktop, css, true, true);
3747 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3748 _("Text: Change font style"));
3749 sp_repr_css_attr_unref (css);
3751 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3752 }
3754 void
3755 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
3756 gpointer data)
3757 {
3758 if (g_object_get_data (G_OBJECT (button), "block")) {
3759 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3760 return;
3761 }
3763 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3764 SPCSSAttr *css = sp_repr_css_attr_new ();
3765 int prop = GPOINTER_TO_INT(data);
3767 switch (prop)
3768 {
3769 case 0:
3770 {
3771 sp_repr_css_set_property (css, "writing-mode", "lr");
3772 break;
3773 }
3775 case 1:
3776 {
3777 sp_repr_css_set_property (css, "writing-mode", "tb");
3778 break;
3779 }
3780 }
3782 SPStyle *query =
3783 sp_style_new (SP_ACTIVE_DOCUMENT);
3784 int result_numbers =
3785 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3787 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3788 if (result_numbers == QUERY_STYLE_NOTHING)
3789 {
3790 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3791 }
3793 sp_desktop_set_style (desktop, css, true, true);
3794 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3795 _("Text: Change orientation"));
3796 sp_repr_css_attr_unref (css);
3798 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3799 }
3801 gboolean
3802 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3803 {
3804 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3805 if (!desktop) return FALSE;
3807 switch (get_group0_keyval (event)) {
3808 case GDK_Escape: // defocus
3809 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3810 return TRUE; // I consumed the event
3811 break;
3812 case GDK_Return: // defocus
3813 case GDK_KP_Enter:
3814 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3815 return TRUE; // I consumed the event
3816 break;
3817 }
3818 return FALSE;
3819 }
3821 gboolean
3822 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3823 {
3824 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3825 if (!desktop) return FALSE;
3827 switch (get_group0_keyval (event)) {
3828 case GDK_Escape: // defocus
3829 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3830 sp_text_toolbox_selection_changed (NULL, tbl); // update
3831 return TRUE; // I consumed the event
3832 break;
3833 }
3834 return FALSE;
3835 }
3837 gboolean
3838 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3839 {
3840 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3841 if (!desktop) return FALSE;
3843 switch (get_group0_keyval (event)) {
3844 case GDK_Escape: // defocus
3845 gtk_widget_hide (w);
3846 visible = false;
3847 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3848 return TRUE; // I consumed the event
3849 break;
3850 }
3851 return FALSE;
3852 }
3855 void
3856 sp_text_toolbox_size_changed (GtkComboBox *cbox,
3857 GObject *tbl)
3858 {
3859 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3861 if (g_object_get_data (tbl, "size-block")) return;
3863 #if GTK_CHECK_VERSION(2,6,0)
3864 char *text = gtk_combo_box_get_active_text (cbox);
3865 #else // GTK_CHECK_VERSION(2,6,0)
3866 GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3867 GtkTreeIter iter;
3868 char *text = NULL;
3870 if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3871 gtk_tree_model_get (model, &iter, 0, &text, -1);
3872 #endif // GTK_CHECK_VERSION(2,6,0)
3874 SPCSSAttr *css = sp_repr_css_attr_new ();
3875 sp_repr_css_set_property (css, "font-size", text);
3876 free (text);
3878 SPStyle *query =
3879 sp_style_new (SP_ACTIVE_DOCUMENT);
3880 int result_numbers =
3881 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3883 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3884 if (result_numbers == QUERY_STYLE_NOTHING)
3885 {
3886 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3887 }
3889 sp_style_unref(query);
3891 sp_desktop_set_style (desktop, css, true, true);
3892 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
3893 _("Text: Change font size"));
3894 sp_repr_css_attr_unref (css);
3897 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3898 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3899 }
3901 void
3902 sp_text_toolbox_text_popdown_clicked (GtkButton *button,
3903 GObject *tbl)
3904 {
3905 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3906 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3907 int x, y;
3909 if (!visible)
3910 {
3911 gdk_window_get_origin (widget->window, &x, &y);
3912 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
3913 gtk_widget_show_all (popdown);
3915 gdk_pointer_grab (widget->window, TRUE,
3916 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3917 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3918 GDK_POINTER_MOTION_MASK),
3919 NULL, NULL, GDK_CURRENT_TIME);
3921 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3923 visible = true;
3924 }
3925 else
3926 {
3927 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3928 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3929 gtk_widget_hide (popdown);
3930 visible = false;
3931 }
3932 }
3934 gboolean
3935 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
3936 GdkEventFocus *event,
3937 GObject *tbl)
3938 {
3939 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3940 return FALSE;
3941 }
3943 gboolean
3944 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
3945 GdkEventFocus *event,
3946 GObject *tbl)
3947 {
3948 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3950 gtk_widget_hide (popdown);
3951 visible = false;
3952 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3953 return TRUE;
3954 }
3956 void
3957 cell_data_func (GtkTreeViewColumn *column,
3958 GtkCellRenderer *cell,
3959 GtkTreeModel *tree_model,
3960 GtkTreeIter *iter,
3961 gpointer data)
3962 {
3963 char *family,
3964 *family_escaped,
3965 *sample_escaped;
3967 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3969 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3971 family_escaped = g_markup_escape_text (family, -1);
3972 sample_escaped = g_markup_escape_text (sample, -1);
3974 std::stringstream markup;
3975 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3976 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3978 free (family);
3979 free (family_escaped);
3980 free (sample_escaped);
3981 }
3983 static void delete_completion(GObject *obj, GtkWidget *entry) {
3984 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3985 if (completion) {
3986 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3987 g_object_unref (completion);
3988 }
3989 }
3991 GtkWidget*
3992 sp_text_toolbox_new (SPDesktop *desktop)
3993 {
3994 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
3996 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3997 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3999 GtkTooltips *tt = gtk_tooltips_new();
4000 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
4002 ////////////Family
4003 //Window
4004 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4005 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
4007 //Entry
4008 GtkWidget *entry = gtk_entry_new ();
4009 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
4010 GtkEntryCompletion *completion = gtk_entry_completion_new ();
4011 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
4012 gtk_entry_completion_set_text_column (completion, 0);
4013 gtk_entry_completion_set_minimum_key_length (completion, 1);
4014 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
4015 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
4016 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
4017 aux_toolbox_space (tbl, 1);
4018 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
4019 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
4021 //Button
4022 GtkWidget *button = gtk_button_new ();
4023 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
4024 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
4026 //Popdown
4027 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
4028 GtkWidget *treeview = gtk_tree_view_new ();
4030 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
4031 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
4032 gtk_tree_view_column_pack_start (column, cell, FALSE);
4033 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
4034 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
4035 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4037 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
4038 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
4039 #if GTK_CHECK_VERSION(2,6,0)
4040 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
4041 #endif // GTK_CHECK_VERSION(2,6,0)
4043 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
4045 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
4046 gtk_container_add (GTK_CONTAINER (sw), treeview);
4048 gtk_container_add (GTK_CONTAINER (window), sw);
4049 gtk_widget_set_size_request (window, 300, 450);
4051 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
4052 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
4053 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
4055 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
4057 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
4058 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
4060 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
4061 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
4063 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
4064 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
4065 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
4066 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
4067 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
4069 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
4070 aux_toolbox_space (tbl, 1);
4071 GtkWidget *box = gtk_event_box_new ();
4072 gtk_container_add (GTK_CONTAINER (box), image);
4073 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
4074 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
4075 GtkTooltips *tooltips = gtk_tooltips_new ();
4076 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
4077 gtk_widget_hide (GTK_WIDGET (box));
4078 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
4080 ////////////Size
4081 const char *sizes[] = {
4082 "4", "6", "8", "9", "10", "11", "12", "13", "14",
4083 "16", "18", "20", "22", "24", "28",
4084 "32", "36", "40", "48", "56", "64", "72", "144"
4085 };
4087 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
4088 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
4089 gtk_widget_set_size_request (cbox, 80, -1);
4090 aux_toolbox_space (tbl, 1);
4091 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
4092 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
4093 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
4094 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
4096 //spacer
4097 aux_toolbox_space (tbl, 4);
4098 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4100 ////////////Text anchor
4101 GtkWidget *group = gtk_radio_button_new (NULL);
4102 GtkWidget *row = gtk_hbox_new (FALSE, 4);
4103 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
4105 // left
4106 GtkWidget *rbutton = group;
4107 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4108 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4109 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4111 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4112 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
4113 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
4114 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
4116 // center
4117 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4118 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4119 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
4120 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4122 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4123 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
4124 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
4125 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
4127 // right
4128 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4129 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4130 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
4131 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4133 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4134 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
4135 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
4136 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
4138 // fill
4139 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4140 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4141 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
4142 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4144 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4145 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
4146 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
4147 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
4149 aux_toolbox_space (tbl, 1);
4150 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4152 //spacer
4153 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4155 ////////////Text style
4156 row = gtk_hbox_new (FALSE, 4);
4158 // bold
4159 rbutton = gtk_toggle_button_new ();
4160 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4161 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
4162 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4163 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
4165 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4166 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
4167 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
4169 // italic
4170 rbutton = gtk_toggle_button_new ();
4171 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4172 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
4173 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4174 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
4176 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4177 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
4178 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
4180 aux_toolbox_space (tbl, 1);
4181 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4183 //spacer
4184 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4186 ////////////Text orientation
4187 group = gtk_radio_button_new (NULL);
4188 row = gtk_hbox_new (FALSE, 4);
4189 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4191 // horizontal
4192 rbutton = group;
4193 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4194 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4195 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4196 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4198 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4199 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4200 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4202 // vertical
4203 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4204 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4205 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4206 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4207 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4209 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4210 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4211 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4212 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4215 //watch selection
4216 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4218 sigc::connection *c_selection_changed =
4219 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4220 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4221 pool->add_connection ("selection-changed", c_selection_changed);
4223 sigc::connection *c_selection_modified =
4224 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4225 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4226 pool->add_connection ("selection-modified", c_selection_modified);
4228 sigc::connection *c_subselection_changed =
4229 new sigc::connection (desktop->connectToolSubselectionChanged
4230 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4231 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4233 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4236 #if 0
4237 // horizontal
4238 {
4239 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
4240 GtkWidget *b = group = gtk_radio_button_new (NULL);
4241 gtk_container_add (GTK_CONTAINER (b), px);
4242 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
4243 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4244 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4245 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4246 }
4248 // vertical
4249 {
4250 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
4251 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4252 gtk_container_add (GTK_CONTAINER (b), px);
4253 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
4254 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4255 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4256 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4257 }
4259 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4261 // letter spacing
4262 {
4263 {
4264 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
4265 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4266 gtk_container_add (GTK_CONTAINER (hb), image);
4267 gtk_widget_show(image);
4268 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4269 }
4271 {
4272 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
4273 "tools.text", "letter_spacing", 0.0,
4274 us, tbl, FALSE, NULL,
4275 -1000.0, 1000.0, 0.1, 0.1,
4276 sp_text_letter_changed, 0.1, 1);
4277 gtk_widget_set_size_request (hb, 45, 6);
4278 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4279 }
4280 }
4282 // line spacing
4283 {
4284 {
4285 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
4286 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4287 gtk_container_add (GTK_CONTAINER (hb), image);
4288 gtk_widget_show(image);
4289 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4290 }
4292 {
4293 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
4294 "tools.text", "line_spacing", 0,
4295 us, tbl, FALSE, NULL,
4296 -1000.0, 1000.0, 0.1, 0.1,
4297 sp_text_line_changed, 0.1, 1);
4298 gtk_widget_set_size_request (hb, 45, 0);
4299 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
4300 }
4301 }
4303 {
4304 // horizontal kerning/vertical kerning units menu: create
4305 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
4306 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
4307 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
4309 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4311 // horizontal kerning
4312 {
4313 {
4314 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
4315 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4316 gtk_container_add (GTK_CONTAINER (hb), image);
4317 gtk_widget_show(image);
4318 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4319 }
4321 {
4322 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
4323 "tools.text", "horizontal_kerning", 0,
4324 us, tbl, FALSE, NULL,
4325 -100.00, 100.00, 0.01, 0.1,
4326 sp_text_horiz_kern_changed);
4327 gtk_widget_set_size_request (hb, 45, 0);
4328 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4329 }
4330 }
4332 // vertical kerning
4333 {
4334 {
4335 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
4336 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4337 gtk_container_add (GTK_CONTAINER (hb), image);
4338 gtk_widget_show(image);
4339 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4340 }
4342 {
4343 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
4344 "tools.text", "vertical_kerning", 0,
4345 us, tbl, FALSE, NULL,
4346 -100.00, 100.00, 0.01, 0.1,
4347 sp_text_vert_kern_changed);
4348 gtk_widget_set_size_request (hb, 45, 0);
4349 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
4350 }
4351 }
4353 // add the units menu
4354 gtk_widget_show(us);
4355 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
4356 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
4357 }
4359 // letter rotation
4360 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4361 {
4362 {
4363 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
4364 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4365 gtk_container_add (GTK_CONTAINER (hb), image);
4366 gtk_widget_show(image);
4367 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4368 }
4369 {
4370 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
4371 "tools.text", "letter_rotation", 0,
4372 us, tbl, FALSE, NULL,
4373 -180.0, 180.0, 0.1, 0.1,
4374 sp_text_letter_rotation_changed, 0.1, 1);
4375 gtk_widget_set_size_request (hb, 45, 0);
4376 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4377 }
4378 // rotation degree label
4379 {
4380 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4381 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4382 }
4383 }
4385 // Remove Manual Kerns
4386 {
4387 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4388 GtkWidget *button = gtk_button_new ();
4389 gtk_container_add (GTK_CONTAINER (button), px);
4390 gtk_widget_show(button);
4391 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4392 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4393 gtk_widget_set_sensitive(button, TRUE);
4394 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4395 }
4396 #endif
4398 gtk_widget_show_all (tbl);
4399 return tbl;
4401 } // end of sp_text_toolbox_new()
4403 }//<unnamed> namespace
4406 //#########################
4407 //## Connector Toolbox ##
4408 //#########################
4410 static void sp_connector_path_set_avoid(void)
4411 {
4412 cc_selection_set_avoid(true);
4413 }
4416 static void sp_connector_path_set_ignore(void)
4417 {
4418 cc_selection_set_avoid(false);
4419 }
4423 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4424 {
4425 // quit if run by the _changed callbacks
4426 if (g_object_get_data( tbl, "freeze" )) {
4427 return;
4428 }
4430 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4431 SPDocument *doc = sp_desktop_document(desktop);
4433 if (!sp_document_get_undo_sensitive(doc))
4434 {
4435 return;
4436 }
4438 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4440 if ( repr->attribute("inkscape:connector-spacing") ) {
4441 gdouble priorValue = gtk_adjustment_get_value(adj);
4442 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4443 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4444 return;
4445 }
4446 } else if ( adj->value == defaultConnSpacing ) {
4447 return;
4448 }
4450 // in turn, prevent callbacks from responding
4451 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4453 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4454 SP_OBJECT(desktop->namedview)->updateRepr();
4456 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4457 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4458 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4459 NR::Matrix m = NR::identity();
4460 avoid_item_move(&m, item);
4461 }
4463 if (items) {
4464 g_slist_free(items);
4465 }
4467 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4468 _("Change connector spacing"));
4470 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4472 spinbutton_defocus(GTK_OBJECT(tbl));
4473 }
4475 static void sp_connector_graph_layout(void)
4476 {
4477 if (!SP_ACTIVE_DESKTOP) return;
4479 // hack for clones, see comment in align-and-distribute.cpp
4480 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4481 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4483 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4485 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4487 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4488 }
4490 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject *tbl )
4491 {
4492 if ( gtk_toggle_action_get_active( act ) ) {
4493 prefs_set_string_attribute("tools.connector", "directedlayout",
4494 "true");
4495 } else {
4496 prefs_set_string_attribute("tools.connector", "directedlayout",
4497 "false");
4498 }
4499 }
4501 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject *tbl )
4502 {
4503 if ( gtk_toggle_action_get_active( act ) ) {
4504 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4505 "true");
4506 } else {
4507 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4508 "false");
4509 }
4510 }
4513 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4514 {
4515 prefs_set_double_attribute("tools.connector", "length", adj->value);
4516 spinbutton_defocus(GTK_OBJECT(tbl));
4517 }
4519 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4520 gchar const *name, gchar const *old_value, gchar const *new_value,
4521 bool is_interactive, gpointer data)
4522 {
4523 GtkWidget *tbl = GTK_WIDGET(data);
4525 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4526 return;
4527 }
4528 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4529 return;
4530 }
4532 GtkAdjustment *adj = (GtkAdjustment*)
4533 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4534 gdouble spacing = defaultConnSpacing;
4535 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4537 gtk_adjustment_set_value(adj, spacing);
4538 }
4541 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4542 NULL, /* child_added */
4543 NULL, /* child_removed */
4544 connector_tb_event_attr_changed,
4545 NULL, /* content_changed */
4546 NULL /* order_changed */
4547 };
4550 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
4551 {
4552 {
4553 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
4554 _("Avoid"),
4555 _("Make connectors avoid selected objects"),
4556 "connector_avoid",
4557 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4558 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
4559 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4560 }
4562 {
4563 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
4564 _("Ignore"),
4565 _("Make connectors ignore selected objects"),
4566 "connector_ignore",
4567 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4568 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
4569 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4570 }
4572 EgeAdjustmentAction* eact = 0;
4574 // Spacing spinbox
4575 eact = create_adjustment_action( "ConnectorSpacingAction",
4576 _("Spacing:"), _("The amount of space left around objects by auto-routing connectors"),
4577 "tools.connector", "spacing", defaultConnSpacing,
4578 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
4579 0, 100, 1.0, 10.0,
4580 0, 0, 0,
4581 connector_spacing_changed, 1, 0 );
4582 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4584 // Graph (connector network) layout
4585 {
4586 InkAction* inky = ink_action_new( "ConnectorGraphAction",
4587 _("Graph"),
4588 _("Nicely arrange selected connector network"),
4589 "graph_layout",
4590 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4591 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
4592 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4593 }
4595 // Default connector length spinbox
4596 eact = create_adjustment_action( "ConnectorLengthAction",
4597 _("Length:"), _("Ideal length for connectors when layout is applied"),
4598 "tools.connector", "length", 100,
4599 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
4600 10, 1000, 10.0, 100.0,
4601 0, 0, 0,
4602 connector_length_changed, 1, 0 );
4603 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4606 // Directed edges toggle button
4607 {
4608 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
4609 _("Downwards"),
4610 _("Make connectors with end-markers (arrows) point downwards"),
4611 "directed_graph",
4612 Inkscape::ICON_SIZE_DECORATION );
4613 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4615 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
4616 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4617 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4619 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
4620 }
4622 // Avoid overlaps toggle button
4623 {
4624 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
4625 _("Remove overlaps"),
4626 _("Do not allow overlapping shapes"),
4627 "remove_overlaps",
4628 Inkscape::ICON_SIZE_DECORATION );
4629 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4631 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
4632 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4633 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4635 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
4636 }
4638 // Code to watch for changes to the connector-spacing attribute in
4639 // the XML.
4640 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4641 g_assert(repr != NULL);
4643 purge_repr_listener( holder, holder );
4645 if (repr) {
4646 g_object_set_data( holder, "repr", repr );
4647 Inkscape::GC::anchor(repr);
4648 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
4649 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
4650 }
4651 } // end of sp_connector_toolbox_prep()
4653 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* tbl)
4654 {
4655 gint channels = ege_select_one_action_get_active( act );
4656 flood_channels_set_channels( channels );
4657 }
4659 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject *tbl)
4660 {
4661 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4662 }
4664 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject *tbl)
4665 {
4666 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
4667 }
4669 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
4670 {
4671 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
4672 SPUnit const *unit = tracker->getActiveUnit();
4675 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
4676 }
4678 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
4679 {
4680 // FIXME: make defaults settable via Inkscape Options
4681 struct KeyValue {
4682 char const *key;
4683 double value;
4684 } const key_values[] = {
4685 {"threshold", 15},
4686 {"offset", 0.0}
4687 };
4689 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
4690 KeyValue const &kv = key_values[i];
4691 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
4692 if ( adj ) {
4693 gtk_adjustment_set_value(adj, kv.value);
4694 }
4695 }
4697 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
4698 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
4699 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
4700 ege_select_one_action_set_active( autogap_action, 0 );
4701 }
4703 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4704 {
4705 EgeAdjustmentAction* eact = 0;
4707 {
4708 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4710 GList* items = 0;
4711 gint count = 0;
4712 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
4713 {
4714 GtkTreeIter iter;
4715 gtk_list_store_append( model, &iter );
4716 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4717 count++;
4718 }
4719 g_list_free( items );
4720 items = 0;
4721 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by:"), _(""), NULL, GTK_TREE_MODEL(model) );
4722 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
4723 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
4724 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
4725 g_object_set_data( holder, "channels_action", act1 );
4726 }
4728 // Spacing spinbox
4729 {
4730 eact = create_adjustment_action(
4731 "ThresholdAction",
4732 _("Threshold:"),
4733 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
4734 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
4735 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
4736 0, 0, 0,
4737 paintbucket_threshold_changed, 1, 0 );
4739 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4740 }
4742 // Create the units menu.
4743 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
4744 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
4745 g_object_set_data( holder, "tracker", tracker );
4746 {
4747 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), _("") );
4748 gtk_action_group_add_action( mainActions, act );
4749 }
4751 // Offset spinbox
4752 {
4753 eact = create_adjustment_action(
4754 "OffsetAction",
4755 _("Grow/shrink by:"),
4756 _("The amount to grow (positive) or shrink (negative) the created fill path"),
4757 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
4758 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
4759 0, 0, 0,
4760 paintbucket_offset_changed, 1, 2);
4761 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
4763 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4764 }
4766 /* Auto Gap */
4767 {
4768 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4770 GList* items = 0;
4771 gint count = 0;
4772 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
4773 {
4774 GtkTreeIter iter;
4775 gtk_list_store_append( model, &iter );
4776 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4777 count++;
4778 }
4779 g_list_free( items );
4780 items = 0;
4781 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Fill gaps:"), _(""), NULL, GTK_TREE_MODEL(model) );
4782 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
4783 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
4784 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
4785 g_object_set_data( holder, "autogap_action", act2 );
4786 }
4788 /* Reset */
4789 {
4790 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
4791 _("Defaults"),
4792 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
4793 GTK_STOCK_CLEAR );
4794 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
4795 gtk_action_group_add_action( mainActions, act );
4796 gtk_action_set_sensitive( act, TRUE );
4797 }
4799 }
4801 /*
4802 Local Variables:
4803 mode:c++
4804 c-file-style:"stroustrup"
4805 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4806 indent-tabs-mode:nil
4807 fill-column:99
4808 End:
4809 */
4810 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :