67338cbcf627f00e445bb19f11b873db5b451abf
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-context.h"
68 #include "sp-star.h"
69 #include "sp-spiral.h"
70 #include "sp-ellipse.h"
71 #include "sp-text.h"
72 #include "sp-flowtext.h"
73 #include "style.h"
74 #include "selection.h"
75 #include "document-private.h"
76 #include "desktop-style.h"
77 #include "../libnrtype/font-lister.h"
78 #include "../connection-pool.h"
79 #include "../prefs-utils.h"
80 #include "../inkscape-stock.h"
81 #include "icon.h"
82 #include "graphlayout/graphlayout.h"
84 #include "mod360.h"
86 #include "toolbox.h"
88 #include "flood-context.h"
90 #include "ink-action.h"
91 #include "ege-adjustment-action.h"
92 #include "ege-output-action.h"
93 #include "ege-select-one-action.h"
94 #include "helper/unit-tracker.h"
96 using Inkscape::UnitTracker;
98 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
99 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
101 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
102 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
103 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
104 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
105 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
110 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
112 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
113 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
114 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
116 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
119 static struct {
120 gchar const *type_name;
121 gchar const *data_name;
122 sp_verb_t verb;
123 sp_verb_t doubleclick_verb;
124 } const tools[] = {
125 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
126 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
127 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
128 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
129 // { "SP3DBoxContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
130 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
131 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
132 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
133 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
134 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
135 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
136 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
137 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
138 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
139 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
140 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
141 { NULL, NULL, 0, 0 }
142 };
144 static struct {
145 gchar const *type_name;
146 gchar const *data_name;
147 GtkWidget *(*create_func)(SPDesktop *desktop);
148 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
149 gchar const *ui_name;
150 gint swatch_verb_id;
151 gchar const *swatch_tool;
152 gchar const *swatch_tip;
153 } const aux_toolboxes[] = {
154 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
155 SP_VERB_INVALID, 0, 0},
156 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
157 SP_VERB_INVALID, 0, 0},
158 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
159 SP_VERB_INVALID, 0, 0},
160 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
161 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
162 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
163 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
164 { "SP3DBoxContext", "3dbox_toolbox", 0, sp_3dbox_toolbox_prep, "3DBoxToolbar",
165 SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
166 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
167 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
168 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
169 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
170 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
171 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
172 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
173 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
174 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
175 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
176 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
177 SP_VERB_INVALID, 0, 0},
178 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
179 SP_VERB_INVALID, 0, 0},
180 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
181 SP_VERB_INVALID, 0, 0},
182 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
183 SP_VERB_INVALID, 0, 0},
184 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
185 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
186 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
187 };
190 static gchar const * ui_descr =
191 "<ui>"
192 " <toolbar name='SelectToolbar'>"
193 " <toolitem action='ObjectRotate90CCW' />"
194 " <toolitem action='ObjectRotate90' />"
195 " <toolitem action='ObjectFlipHorizontally' />"
196 " <toolitem action='ObjectFlipVertically' />"
197 " <separator />"
198 " <toolitem action='SelectionToBack' />"
199 " <toolitem action='SelectionLower' />"
200 " <toolitem action='SelectionRaise' />"
201 " <toolitem action='SelectionToFront' />"
202 " <separator />"
203 " <toolitem action='XAction' />"
204 " <toolitem action='YAction' />"
205 " <toolitem action='WidthAction' />"
206 " <toolitem action='LockAction' />"
207 " <toolitem action='HeightAction' />"
208 " <toolitem action='UnitsAction' />"
209 " <separator />"
210 " <toolitem action='transform_stroke' />"
211 " <toolitem action='transform_corners' />"
212 " <toolitem action='transform_gradient' />"
213 " <toolitem action='transform_pattern' />"
214 " </toolbar>"
216 " <toolbar name='NodeToolbar'>"
217 " <toolitem action='NodeInsertAction' />"
218 " <toolitem action='NodeDeleteAction' />"
219 " <separator />"
220 " <toolitem action='NodeJoinAction' />"
221 " <toolitem action='NodeJoinSegmentAction' />"
222 " <toolitem action='NodeDeleteSegmentAction' />"
223 " <toolitem action='NodeBreakAction' />"
224 " <separator />"
225 " <toolitem action='NodeCuspAction' />"
226 " <toolitem action='NodeSmoothAction' />"
227 " <toolitem action='NodeSymmetricAction' />"
228 " <separator />"
229 " <toolitem action='NodeLineAction' />"
230 " <toolitem action='NodeCurveAction' />"
231 " <separator />"
232 " <toolitem action='ObjectToPath' />"
233 " <toolitem action='StrokeToPath' />"
234 " <separator />"
235 " <toolitem action='NodesShowHandlesAction' />"
236 " </toolbar>"
238 " <toolbar name='ZoomToolbar'>"
239 " <toolitem action='ZoomIn' />"
240 " <toolitem action='ZoomOut' />"
241 " <separator />"
242 " <toolitem action='ZoomSelection' />"
243 " <toolitem action='ZoomDrawing' />"
244 " <toolitem action='ZoomPage' />"
245 " <toolitem action='ZoomPageWidth' />"
246 " <separator />"
247 " <toolitem action='ZoomPrev' />"
248 " <toolitem action='ZoomNext' />"
249 " <separator />"
250 " <toolitem action='Zoom1:0' />"
251 " <toolitem action='Zoom1:2' />"
252 " <toolitem action='Zoom2:1' />"
253 " </toolbar>"
255 " <toolbar name='StarToolbar'>"
256 " <separator />"
257 " <toolitem action='StarStateAction' />"
258 " <separator />"
259 " <toolitem action='FlatAction' />"
260 " <separator />"
261 " <toolitem action='MagnitudeAction' />"
262 " <toolitem action='SpokeAction' />"
263 " <toolitem action='RoundednessAction' />"
264 " <toolitem action='RandomizationAction' />"
265 " <separator />"
266 " <toolitem action='StarResetAction' />"
267 " </toolbar>"
269 " <toolbar name='RectToolbar'>"
270 " <toolitem action='RectStateAction' />"
271 " <toolitem action='RectWidthAction' />"
272 " <toolitem action='RectHeightAction' />"
273 " <toolitem action='RadiusXAction' />"
274 " <toolitem action='RadiusYAction' />"
275 " <toolitem action='RectUnitsAction' />"
276 " <separator />"
277 " <toolitem action='RectResetAction' />"
278 " </toolbar>"
280 " <toolbar name='3DBoxToolbar'>"
281 " <toolitem action='3DBoxVPXAction' />"
282 " <toolitem action='3DBoxVPYAction' />"
283 " <toolitem action='3DBoxVPZAction' />"
284 " </toolbar>"
286 " <toolbar name='SpiralToolbar'>"
287 " <toolitem action='SpiralStateAction' />"
288 " <toolitem action='SpiralRevolutionAction' />"
289 " <toolitem action='SpiralExpansionAction' />"
290 " <toolitem action='SpiralT0Action' />"
291 " <separator />"
292 " <toolitem action='SpiralResetAction' />"
293 " </toolbar>"
295 " <toolbar name='PenToolbar'>"
296 " </toolbar>"
298 " <toolbar name='PencilToolbar'>"
299 " </toolbar>"
301 " <toolbar name='CalligraphyToolbar'>"
302 " <separator />"
303 " <toolitem action='CalligraphyWidthAction' />"
304 " <toolitem action='ThinningAction' />"
305 " <separator />"
306 " <toolitem action='AngleAction' />"
307 " <toolitem action='FixationAction' />"
308 " <toolitem action='CapRoundingAction' />"
309 " <separator />"
310 " <toolitem action='TremorAction' />"
311 " <toolitem action='WiggleAction' />"
312 " <toolitem action='MassAction' />"
313 " <separator />"
314 " <toolitem action='TraceAction' />"
315 " <toolitem action='PressureAction' />"
316 " <toolitem action='TiltAction' />"
317 " <toolitem action='CalligraphyResetAction' />"
318 " </toolbar>"
320 " <toolbar name='ArcToolbar'>"
321 " <toolitem action='ArcStateAction' />"
322 " <separator />"
323 " <toolitem action='ArcStartAction' />"
324 " <toolitem action='ArcEndAction' />"
325 " <separator />"
326 " <toolitem action='ArcOpenAction' />"
327 " <separator />"
328 " <toolitem action='ArcResetAction' />"
329 " <separator />"
330 " </toolbar>"
332 " <toolbar name='PaintbucketToolbar'>"
333 " <toolitem action='ChannelsAction' />"
334 " <separator />"
335 " <toolitem action='ThresholdAction' />"
336 " <separator />"
337 " <toolitem action='OffsetAction' />"
338 " <toolitem action='PaintbucketUnitsAction' />"
339 " <separator />"
340 " <toolitem action='AutoGapAction' />"
341 " <separator />"
342 " <toolitem action='PaintbucketResetAction' />"
343 " </toolbar>"
345 " <toolbar name='DropperToolbar'>"
346 " <toolitem action='DropperPickAlphaAction' />"
347 " <toolitem action='DropperSetAlphaAction' />"
348 " </toolbar>"
350 " <toolbar name='ConnectorToolbar'>"
351 " <toolitem action='ConnectorAvoidAction' />"
352 " <toolitem action='ConnectorIgnoreAction' />"
353 " <toolitem action='ConnectorSpacingAction' />"
354 " <toolitem action='ConnectorGraphAction' />"
355 " <toolitem action='ConnectorLengthAction' />"
356 " <toolitem action='ConnectorDirectedAction' />"
357 " <toolitem action='ConnectorOverlapAction' />"
358 " </toolbar>"
360 "</ui>"
361 ;
363 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
365 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
367 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
368 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
370 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
371 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
373 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
374 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
376 /* Global text entry widgets necessary for update */
377 /* GtkWidget *dropper_rgb_entry,
378 *dropper_opacity_entry ; */
379 // should be made a private member once this is converted to class
381 static void delete_connection(GObject *obj, sigc::connection *connection) {
382 connection->disconnect();
383 delete connection;
384 }
386 static void purge_repr_listener( GObject* obj, GObject* tbl )
387 {
388 (void)obj;
389 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
390 if (oldrepr) { // remove old listener
391 sp_repr_remove_listener_by_data(oldrepr, tbl);
392 Inkscape::GC::release(oldrepr);
393 oldrepr = 0;
394 g_object_set_data( tbl, "repr", NULL );
395 }
396 }
398 GtkWidget *
399 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
400 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
401 Inkscape::UI::View::View *view, GtkTooltips *tt)
402 {
403 SPAction *action = verb->get_action(view);
404 if (!action) return NULL;
406 SPAction *doubleclick_action;
407 if (doubleclick_verb)
408 doubleclick_action = doubleclick_verb->get_action(view);
409 else
410 doubleclick_action = NULL;
412 /* fixme: Handle sensitive/unsensitive */
413 /* fixme: Implement sp_button_new_from_action */
414 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
415 gtk_widget_show(b);
416 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
418 return b;
419 }
421 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
422 Inkscape::UI::View::View *view, GtkTooltips *tt)
423 {
424 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
425 }
427 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
428 Inkscape::UI::View::View *view, GtkTooltips *tt)
429 {
430 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
431 }
434 static void trigger_sp_action( GtkAction* act, gpointer user_data )
435 {
436 SPAction* targetAction = SP_ACTION(user_data);
437 if ( targetAction ) {
438 sp_action_perform( targetAction, NULL );
439 }
440 }
442 static void sp_action_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data)
443 {
444 if ( data ) {
445 GtkAction* act = GTK_ACTION(data);
446 gtk_action_set_sensitive( act, sensitive );
447 }
448 }
450 static SPActionEventVector action_event_vector = {
451 {NULL},
452 NULL,
453 NULL,
454 sp_action_action_set_sensitive,
455 NULL,
456 NULL
457 };
459 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
460 {
461 GtkAction* act = 0;
463 SPAction* targetAction = verb->get_action(view);
464 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
465 act = GTK_ACTION(inky);
466 gtk_action_set_sensitive( act, targetAction->sensitive );
468 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
470 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
471 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
473 return act;
474 }
476 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
477 {
478 Inkscape::UI::View::View *view = desktop;
479 gint verbsToUse[] = {
480 // disabled until we have icons for them:
481 //find
482 //SP_VERB_EDIT_TILE,
483 //SP_VERB_EDIT_UNTILE,
484 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
485 SP_VERB_DIALOG_DISPLAY,
486 SP_VERB_DIALOG_FILL_STROKE,
487 SP_VERB_DIALOG_NAMEDVIEW,
488 SP_VERB_DIALOG_TEXT,
489 SP_VERB_DIALOG_XML_EDITOR,
490 SP_VERB_EDIT_CLONE,
491 SP_VERB_EDIT_COPY,
492 SP_VERB_EDIT_CUT,
493 SP_VERB_EDIT_DUPLICATE,
494 SP_VERB_EDIT_PASTE,
495 SP_VERB_EDIT_REDO,
496 SP_VERB_EDIT_UNDO,
497 SP_VERB_EDIT_UNLINK_CLONE,
498 SP_VERB_FILE_EXPORT,
499 SP_VERB_FILE_IMPORT,
500 SP_VERB_FILE_NEW,
501 SP_VERB_FILE_OPEN,
502 SP_VERB_FILE_PRINT,
503 SP_VERB_FILE_SAVE,
504 SP_VERB_OBJECT_TO_CURVE,
505 SP_VERB_SELECTION_GROUP,
506 SP_VERB_SELECTION_OUTLINE,
507 SP_VERB_SELECTION_UNGROUP,
508 SP_VERB_ZOOM_1_1,
509 SP_VERB_ZOOM_1_2,
510 SP_VERB_ZOOM_2_1,
511 SP_VERB_ZOOM_DRAWING,
512 SP_VERB_ZOOM_IN,
513 SP_VERB_ZOOM_NEXT,
514 SP_VERB_ZOOM_OUT,
515 SP_VERB_ZOOM_PAGE,
516 SP_VERB_ZOOM_PAGE_WIDTH,
517 SP_VERB_ZOOM_PREV,
518 SP_VERB_ZOOM_SELECTION,
519 };
521 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
522 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
524 static std::map<SPDesktop*, GtkActionGroup*> groups;
525 GtkActionGroup* mainActions = 0;
526 if ( groups.find(desktop) != groups.end() ) {
527 mainActions = groups[desktop];
528 }
530 if ( !mainActions ) {
531 mainActions = gtk_action_group_new("main");
532 groups[desktop] = mainActions;
533 }
535 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
536 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
537 if ( verb ) {
538 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
539 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
540 gtk_action_group_add_action( mainActions, act );
541 }
542 }
543 }
545 return mainActions;
546 }
549 GtkWidget *
550 sp_tool_toolbox_new()
551 {
552 GtkTooltips *tt = gtk_tooltips_new();
553 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
555 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
556 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
558 gtk_widget_set_sensitive(tb, FALSE);
560 GtkWidget *hb = gtk_handle_box_new();
561 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
562 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
563 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
565 gtk_container_add(GTK_CONTAINER(hb), tb);
566 gtk_widget_show(GTK_WIDGET(tb));
568 sigc::connection* conn = new sigc::connection;
569 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
571 return hb;
572 }
574 static void
575 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
576 {
577 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
578 gtk_widget_queue_resize(child);
579 }
581 static void
582 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
583 {
584 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
585 gtk_widget_queue_resize(child);
586 }
588 GtkWidget *
589 sp_aux_toolbox_new()
590 {
591 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
593 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
594 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
595 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
596 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
597 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
599 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
600 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
602 gtk_widget_set_sensitive(tb, FALSE);
604 GtkWidget *hb = gtk_handle_box_new();
605 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
606 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
607 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
609 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
610 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
612 gtk_container_add(GTK_CONTAINER(hb), tb);
613 gtk_widget_show(GTK_WIDGET(tb));
615 sigc::connection* conn = new sigc::connection;
616 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
618 return hb;
619 }
621 //####################################
622 //# Commands Bar
623 //####################################
625 GtkWidget *
626 sp_commands_toolbox_new()
627 {
628 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
630 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
631 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
632 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
633 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
634 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
636 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
637 gtk_widget_set_sensitive(tb, FALSE);
639 GtkWidget *hb = gtk_handle_box_new();
640 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
641 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
642 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
644 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
645 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
647 gtk_container_add(GTK_CONTAINER(hb), tb);
648 gtk_widget_show(GTK_WIDGET(tb));
650 sigc::connection* conn = new sigc::connection;
651 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
653 return hb;
654 }
657 //####################################
658 //# node editing callbacks
659 //####################################
661 /**
662 * FIXME: Returns current shape_editor in context. // later eliminate this function at all!
663 */
664 static ShapeEditor *get_current_shape_editor()
665 {
666 if (!SP_ACTIVE_DESKTOP) {
667 return NULL;
668 }
670 SPEventContext *event_context = (SP_ACTIVE_DESKTOP)->event_context;
672 if (!SP_IS_NODE_CONTEXT(event_context)) {
673 return NULL;
674 }
676 return SP_NODE_CONTEXT(event_context)->shape_editor;
677 }
680 void
681 sp_node_path_edit_add(void)
682 {
683 ShapeEditor *shape_editor = get_current_shape_editor();
684 if (shape_editor) shape_editor->add_node();
685 }
687 void
688 sp_node_path_edit_delete(void)
689 {
690 ShapeEditor *shape_editor = get_current_shape_editor();
691 if (shape_editor) shape_editor->delete_nodes();
692 }
694 void
695 sp_node_path_edit_delete_segment(void)
696 {
697 ShapeEditor *shape_editor = get_current_shape_editor();
698 if (shape_editor) shape_editor->delete_segment();
699 }
701 void
702 sp_node_path_edit_break(void)
703 {
704 ShapeEditor *shape_editor = get_current_shape_editor();
705 if (shape_editor) shape_editor->break_at_nodes();
706 }
708 void
709 sp_node_path_edit_join(void)
710 {
711 ShapeEditor *shape_editor = get_current_shape_editor();
712 if (shape_editor) shape_editor->join_nodes();
713 }
715 void
716 sp_node_path_edit_join_segment(void)
717 {
718 ShapeEditor *shape_editor = get_current_shape_editor();
719 if (shape_editor) shape_editor->join_segments();
720 }
722 void
723 sp_node_path_edit_toline(void)
724 {
725 ShapeEditor *shape_editor = get_current_shape_editor();
726 if (shape_editor) shape_editor->set_type_of_segments(NR_LINETO);
727 }
729 void
730 sp_node_path_edit_tocurve(void)
731 {
732 ShapeEditor *shape_editor = get_current_shape_editor();
733 if (shape_editor) shape_editor->set_type_of_segments(NR_CURVETO);
734 }
736 void
737 sp_node_path_edit_cusp(void)
738 {
739 ShapeEditor *shape_editor = get_current_shape_editor();
740 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_CUSP);
741 }
743 void
744 sp_node_path_edit_smooth(void)
745 {
746 ShapeEditor *shape_editor = get_current_shape_editor();
747 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SMOOTH);
748 }
750 void
751 sp_node_path_edit_symmetrical(void)
752 {
753 ShapeEditor *shape_editor = get_current_shape_editor();
754 if (shape_editor) shape_editor->set_node_type(Inkscape::NodePath::NODE_SYMM);
755 }
757 static void toggle_show_handles (GtkToggleAction *act, gpointer data) {
758 bool show = gtk_toggle_action_get_active( act );
759 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
760 ShapeEditor *shape_editor = get_current_shape_editor();
761 if (shape_editor) shape_editor->show_handles(show);
762 }
764 //################################
765 //## Node Editing Toolbox ##
766 //################################
768 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
769 {
770 {
771 InkAction* inky = ink_action_new( "NodeInsertAction",
772 _("Insert"),
773 _("Insert new nodes into selected segments"),
774 "node_insert",
775 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
776 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
777 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
778 }
780 {
781 InkAction* inky = ink_action_new( "NodeDeleteAction",
782 _("Delete"),
783 _("Delete selected nodes"),
784 "node_delete",
785 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
786 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
787 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
788 }
790 {
791 InkAction* inky = ink_action_new( "NodeJoinAction",
792 _("Join"),
793 _("Join selected endnodes"),
794 "node_join",
795 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
796 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
797 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
798 }
800 {
801 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
802 _("Join Segment"),
803 _("Join selected endnodes with a new segment"),
804 "node_join_segment",
805 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
806 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
807 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
808 }
810 {
811 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
812 _("Delete Segment"),
813 _("Split path between two non-endpoint nodes"),
814 "node_delete_segment",
815 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
816 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
817 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
818 }
820 {
821 InkAction* inky = ink_action_new( "NodeBreakAction",
822 _("Node Break"),
823 _("Break path at selected nodes"),
824 "node_break",
825 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
826 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
827 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
828 }
830 {
831 InkAction* inky = ink_action_new( "NodeCuspAction",
832 _("Node Cusp"),
833 _("Make selected nodes corner"),
834 "node_cusp",
835 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
836 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
837 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
838 }
840 {
841 InkAction* inky = ink_action_new( "NodeSmoothAction",
842 _("Node Smooth"),
843 _("Make selected nodes smooth"),
844 "node_smooth",
845 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
846 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
847 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
848 }
850 {
851 InkAction* inky = ink_action_new( "NodeSymmetricAction",
852 _("Node Symmetric"),
853 _("Make selected nodes symmetric"),
854 "node_symmetric",
855 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
856 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
857 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
858 }
860 {
861 InkAction* inky = ink_action_new( "NodeLineAction",
862 _("Node Line"),
863 _("Make selected segments lines"),
864 "node_line",
865 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
866 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
867 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
868 }
870 {
871 InkAction* inky = ink_action_new( "NodeCurveAction",
872 _("Node Curve"),
873 _("Make selected segments curves"),
874 "node_curve",
875 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
876 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
877 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
878 }
880 {
881 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
882 _("Show Handles"),
883 _("Show the Bezier handles of selected nodes"),
884 "nodes_show_handles",
885 Inkscape::ICON_SIZE_DECORATION );
886 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
887 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
888 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
889 }
891 } // end of sp_node_toolbox_prep()
894 //########################
895 //## Zoom Toolbox ##
896 //########################
898 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
899 {
900 // no custom GtkAction setup needed
901 } // end of sp_zoom_toolbox_prep()
903 void
904 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
905 {
906 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")));
907 }
910 void
911 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
912 {
913 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")));
914 }
916 void
917 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
918 {
919 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")));
920 }
922 static void
923 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
924 {
925 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
926 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
928 if (old_desktop) {
929 GList *children, *iter;
931 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
932 for ( iter = children ; iter ; iter = iter->next ) {
933 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
934 }
935 g_list_free(children);
936 }
938 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
940 if (desktop) {
941 gtk_widget_set_sensitive(toolbox, TRUE);
942 setup_func(toolbox, desktop);
943 update_func(desktop, desktop->event_context, toolbox);
944 *conn = desktop->connectEventContextChanged
945 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
946 } else {
947 gtk_widget_set_sensitive(toolbox, FALSE);
948 }
950 } // end of toolbox_set_desktop()
953 static void
954 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
955 {
956 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
957 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
958 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
959 // "toolbox.tools" was not set. Fallback to older value
960 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
962 // Copy the setting forwards
963 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
964 }
965 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
967 for (int i = 0 ; tools[i].type_name ; i++ ) {
968 GtkWidget *button =
969 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
970 SP_BUTTON_TYPE_TOGGLE,
971 Inkscape::Verb::get(tools[i].verb),
972 Inkscape::Verb::get(tools[i].doubleclick_verb),
973 desktop,
974 tooltips );
976 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
977 (gpointer)button );
978 }
979 }
982 static void
983 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
984 {
985 gchar const *const tname = ( eventcontext
986 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
987 : NULL );
988 for (int i = 0 ; tools[i].type_name ; i++ ) {
989 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
990 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
991 }
992 }
994 static void
995 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
996 {
997 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
998 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
999 GtkUIManager* mgr = gtk_ui_manager_new();
1000 GError* errVal = 0;
1001 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1002 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
1004 std::map<std::string, GtkWidget*> dataHolders;
1006 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1007 if ( aux_toolboxes[i].prep_func ) {
1008 // converted to GtkActions and UIManager
1010 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
1011 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
1012 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
1013 dataHolders[aux_toolboxes[i].type_name] = kludge;
1014 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
1015 } else {
1017 GtkWidget *sub_toolbox = 0;
1018 if (aux_toolboxes[i].create_func == NULL)
1019 sub_toolbox = sp_empty_toolbox_new(desktop);
1020 else {
1021 sub_toolbox = aux_toolboxes[i].create_func(desktop);
1022 }
1024 gtk_size_group_add_widget( grouper, sub_toolbox );
1026 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
1027 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
1029 }
1030 }
1032 // Second pass to create toolbars *after* all GtkActions are created
1033 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1034 if ( aux_toolboxes[i].prep_func ) {
1035 // converted to GtkActions and UIManager
1037 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
1039 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
1040 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
1042 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
1043 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
1044 g_free( tmp );
1045 tmp = 0;
1047 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1048 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1049 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1050 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1051 }
1052 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1055 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1057 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1058 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1059 swatch->setDesktop( desktop );
1060 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1061 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1062 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1063 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 );
1064 }
1066 gtk_widget_show_all( holder );
1067 sp_set_font_size_smaller( holder );
1069 gtk_size_group_add_widget( grouper, holder );
1071 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1072 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1073 }
1074 }
1076 g_object_unref( G_OBJECT(grouper) );
1077 }
1079 static void
1080 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1081 {
1082 gchar const *tname = ( eventcontext
1083 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1084 : NULL );
1085 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1086 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1087 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1088 gtk_widget_show_all(sub_toolbox);
1089 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1090 } else {
1091 gtk_widget_hide(sub_toolbox);
1092 }
1093 }
1094 }
1096 static void
1097 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1098 {
1099 gchar const * descr =
1100 "<ui>"
1101 " <toolbar name='CommandsToolbar'>"
1102 " <toolitem action='FileNew' />"
1103 " <toolitem action='FileOpen' />"
1104 " <toolitem action='FileSave' />"
1105 " <toolitem action='FilePrint' />"
1106 " <separator />"
1107 " <toolitem action='FileImport' />"
1108 " <toolitem action='FileExport' />"
1109 " <separator />"
1110 " <toolitem action='EditUndo' />"
1111 " <toolitem action='EditRedo' />"
1112 " <separator />"
1113 " <toolitem action='EditCopy' />"
1114 " <toolitem action='EditCut' />"
1115 " <toolitem action='EditPaste' />"
1116 " <separator />"
1117 " <toolitem action='ZoomSelection' />"
1118 " <toolitem action='ZoomDrawing' />"
1119 " <toolitem action='ZoomPage' />"
1120 " <separator />"
1121 " <toolitem action='EditDuplicate' />"
1122 " <toolitem action='EditClone' />"
1123 " <toolitem action='EditUnlinkClone' />"
1124 " <separator />"
1125 " <toolitem action='SelectionGroup' />"
1126 " <toolitem action='SelectionUnGroup' />"
1127 " <separator />"
1128 " <toolitem action='DialogFillStroke' />"
1129 " <toolitem action='DialogText' />"
1130 " <toolitem action='DialogXMLEditor' />"
1131 " <toolitem action='DialogAlignDistribute' />"
1132 " <separator />"
1133 " <toolitem action='DialogPreferences' />"
1134 " <toolitem action='DialogDocumentProperties' />"
1135 " </toolbar>"
1136 "</ui>";
1137 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1140 GtkUIManager* mgr = gtk_ui_manager_new();
1141 GError* errVal = 0;
1143 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1144 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1146 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1147 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1148 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1149 }
1150 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1151 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1152 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1155 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1156 }
1158 static void
1159 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1160 {
1161 }
1163 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1164 {
1165 gtk_widget_show(toolbox_toplevel);
1166 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1168 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1169 if (!shown_toolbox) {
1170 return;
1171 }
1172 gtk_widget_show(toolbox);
1174 // need to show the spacer, or the padding will be off
1175 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1176 gtk_widget_show(spacer);
1178 gtk_widget_show_all(shown_toolbox);
1179 }
1181 void
1182 aux_toolbox_space(GtkWidget *tb, gint space)
1183 {
1184 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1185 }
1187 static GtkWidget *
1188 sp_empty_toolbox_new(SPDesktop *desktop)
1189 {
1190 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1191 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1192 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1194 gtk_widget_show_all(tbl);
1195 sp_set_font_size_smaller (tbl);
1197 return tbl;
1198 }
1200 // helper UI functions
1202 GtkWidget *
1203 sp_tb_spinbutton(
1204 gchar *label, gchar const *tooltip,
1205 gchar const *path, gchar const *data, gdouble def,
1206 GtkWidget *us,
1207 GtkWidget *tbl,
1208 gboolean altx, gchar const *altx_mark,
1209 gdouble lower, gdouble upper, gdouble step, gdouble page,
1210 void (*callback)(GtkAdjustment *, GtkWidget *),
1211 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1212 {
1213 GtkTooltips *tt = gtk_tooltips_new();
1215 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1217 GtkWidget *l = gtk_label_new(label);
1218 gtk_widget_show(l);
1219 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1220 gtk_container_add(GTK_CONTAINER(hb), l);
1222 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1223 lower, upper, step, page, page);
1224 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1225 if (us)
1226 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1228 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1229 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1230 if (altx)
1231 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1232 gtk_widget_set_size_request(sb,
1233 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1234 AUX_SPINBUTTON_HEIGHT);
1235 gtk_widget_show(sb);
1236 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1237 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1238 gtk_container_add(GTK_CONTAINER(hb), sb);
1239 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1241 return hb;
1242 }
1244 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
1245 gchar const *label, gchar const *tooltip,
1246 gchar const *path, gchar const *data, gdouble def,
1247 GtkWidget *focusTarget,
1248 GtkWidget *us,
1249 GObject *dataKludge,
1250 gboolean altx, gchar const *altx_mark,
1251 gdouble lower, gdouble upper, gdouble step, gdouble page,
1252 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
1253 void (*callback)(GtkAdjustment *, GObject *),
1254 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
1255 {
1256 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
1257 lower, upper, step, page, page ) );
1258 if (us) {
1259 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
1260 }
1262 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
1264 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
1266 if ( (descrCount > 0) && descrLabels && descrValues ) {
1267 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
1268 }
1270 if ( focusTarget ) {
1271 ege_adjustment_action_set_focuswidget( act, focusTarget );
1272 }
1274 if ( altx && altx_mark ) {
1275 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
1276 }
1278 if ( dataKludge ) {
1279 g_object_set_data( dataKludge, data, adj );
1280 }
1282 // Using a cast just to make sure we pass in the right kind of function pointer
1283 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
1285 return act;
1286 }
1289 #define MODE_LABEL_WIDTH 70
1291 //########################
1292 //## Star ##
1293 //########################
1295 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1296 {
1297 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1299 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1300 // do not remember prefs if this call is initiated by an undo change, because undoing object
1301 // creation sets bogus values to its attributes before it is deleted
1302 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1303 }
1305 // quit if run by the attr_changed listener
1306 if (g_object_get_data( dataKludge, "freeze" )) {
1307 return;
1308 }
1310 // in turn, prevent listener from responding
1311 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1313 bool modmade = false;
1315 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1316 GSList const *items = selection->itemList();
1317 for (; items != NULL; items = items->next) {
1318 if (SP_IS_STAR((SPItem *) items->data)) {
1319 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1320 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1321 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1322 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1323 + M_PI / (gint)adj->value));
1324 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1325 modmade = true;
1326 }
1327 }
1328 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1329 _("Star: Change number of corners"));
1331 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1332 }
1334 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1335 {
1336 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1338 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1339 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1340 }
1342 // quit if run by the attr_changed listener
1343 if (g_object_get_data( dataKludge, "freeze" )) {
1344 return;
1345 }
1347 // in turn, prevent listener from responding
1348 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1350 bool modmade = false;
1351 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1352 GSList const *items = selection->itemList();
1353 for (; items != NULL; items = items->next) {
1354 if (SP_IS_STAR((SPItem *) items->data)) {
1355 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1357 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1358 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1359 if (r2 < r1) {
1360 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1361 } else {
1362 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1363 }
1365 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1366 modmade = true;
1367 }
1368 }
1370 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1371 _("Star: Change spoke ratio"));
1373 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1374 }
1376 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1377 {
1378 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1379 bool flat = ege_select_one_action_get_active( act ) == 0;
1381 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1382 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1383 flat ? "true" : "false" );
1384 }
1386 // quit if run by the attr_changed listener
1387 if (g_object_get_data( dataKludge, "freeze" )) {
1388 return;
1389 }
1391 // in turn, prevent listener from responding
1392 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1394 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1395 GSList const *items = selection->itemList();
1396 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1397 bool modmade = false;
1399 if ( prop_action ) {
1400 gtk_action_set_sensitive( prop_action, !flat );
1401 }
1403 for (; items != NULL; items = items->next) {
1404 if (SP_IS_STAR((SPItem *) items->data)) {
1405 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1406 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1407 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1408 modmade = true;
1409 }
1410 }
1412 if (modmade) {
1413 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1414 flat ? _("Make polygon") : _("Make star"));
1415 }
1417 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1418 }
1420 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1421 {
1422 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1424 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1425 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1426 }
1428 // quit if run by the attr_changed listener
1429 if (g_object_get_data( dataKludge, "freeze" )) {
1430 return;
1431 }
1433 // in turn, prevent listener from responding
1434 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1436 bool modmade = false;
1438 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1439 GSList const *items = selection->itemList();
1440 for (; items != NULL; items = items->next) {
1441 if (SP_IS_STAR((SPItem *) items->data)) {
1442 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1443 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1444 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1445 modmade = true;
1446 }
1447 }
1448 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1449 _("Star: Change rounding"));
1451 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1452 }
1454 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1455 {
1456 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1458 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1459 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1460 }
1462 // quit if run by the attr_changed listener
1463 if (g_object_get_data( dataKludge, "freeze" )) {
1464 return;
1465 }
1467 // in turn, prevent listener from responding
1468 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1470 bool modmade = false;
1472 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1473 GSList const *items = selection->itemList();
1474 for (; items != NULL; items = items->next) {
1475 if (SP_IS_STAR((SPItem *) items->data)) {
1476 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1477 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1478 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1479 modmade = true;
1480 }
1481 }
1482 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1483 _("Star: Change randomization"));
1485 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1486 }
1489 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1490 gchar const *old_value, gchar const *new_value,
1491 bool is_interactive, gpointer data)
1492 {
1493 GtkWidget *tbl = GTK_WIDGET(data);
1495 // quit if run by the _changed callbacks
1496 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1497 return;
1498 }
1500 // in turn, prevent callbacks from responding
1501 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1503 GtkAdjustment *adj = 0;
1505 if (!strcmp(name, "inkscape:randomized")) {
1506 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1507 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1508 } else if (!strcmp(name, "inkscape:rounded")) {
1509 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1510 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1511 } else if (!strcmp(name, "inkscape:flatsided")) {
1512 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1513 char const *flatsides = repr->attribute("inkscape:flatsided");
1514 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1515 if ( flatsides && !strcmp(flatsides,"false") ) {
1516 ege_select_one_action_set_active( flat_action, 1 );
1517 gtk_action_set_sensitive( prop_action, TRUE );
1518 } else {
1519 ege_select_one_action_set_active( flat_action, 0 );
1520 gtk_action_set_sensitive( prop_action, FALSE );
1521 }
1522 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1523 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1524 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1525 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1526 if (r2 < r1) {
1527 gtk_adjustment_set_value(adj, r2/r1);
1528 } else {
1529 gtk_adjustment_set_value(adj, r1/r2);
1530 }
1531 } else if (!strcmp(name, "sodipodi:sides")) {
1532 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1533 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1534 }
1536 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1537 }
1540 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1541 {
1542 NULL, /* child_added */
1543 NULL, /* child_removed */
1544 star_tb_event_attr_changed,
1545 NULL, /* content_changed */
1546 NULL /* order_changed */
1547 };
1550 /**
1551 * \param selection Should not be NULL.
1552 */
1553 static void
1554 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1555 {
1556 int n_selected = 0;
1557 Inkscape::XML::Node *repr = NULL;
1559 purge_repr_listener( tbl, tbl );
1561 for (GSList const *items = selection->itemList();
1562 items != NULL;
1563 items = items->next)
1564 {
1565 if (SP_IS_STAR((SPItem *) items->data)) {
1566 n_selected++;
1567 repr = SP_OBJECT_REPR((SPItem *) items->data);
1568 }
1569 }
1571 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1573 if (n_selected == 0) {
1574 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1575 } else if (n_selected == 1) {
1576 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1578 if (repr) {
1579 g_object_set_data( tbl, "repr", repr );
1580 Inkscape::GC::anchor(repr);
1581 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1582 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1583 }
1584 } else {
1585 // FIXME: implement averaging of all parameters for multiple selected stars
1586 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1587 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1588 }
1589 }
1592 static void sp_stb_defaults( GtkWidget *widget, GObject *dataKludge )
1593 {
1594 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1595 // callbacks to lump all the changes for all selected objects in one undo step
1597 GtkAdjustment *adj = 0;
1599 // fixme: make settable in prefs!
1600 gint mag = 5;
1601 gdouble prop = 0.5;
1602 gboolean flat = FALSE;
1603 gdouble randomized = 0;
1604 gdouble rounded = 0;
1606 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1607 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1609 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1610 gtk_action_set_sensitive( sb2, !flat );
1612 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1613 gtk_adjustment_set_value(adj, mag);
1614 gtk_adjustment_value_changed(adj);
1616 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1617 gtk_adjustment_set_value(adj, prop);
1618 gtk_adjustment_value_changed(adj);
1620 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1621 gtk_adjustment_set_value(adj, rounded);
1622 gtk_adjustment_value_changed(adj);
1624 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1625 gtk_adjustment_set_value(adj, randomized);
1626 gtk_adjustment_value_changed(adj);
1627 }
1630 void
1631 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1632 {
1633 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1634 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1635 GtkWidget *l = gtk_label_new(NULL);
1636 gtk_label_set_markup(GTK_LABEL(l), title);
1637 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1638 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1639 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1640 }
1643 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1644 {
1645 {
1646 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1647 ege_output_action_set_use_markup( act, TRUE );
1648 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1649 g_object_set_data( holder, "mode_action", act );
1650 }
1652 {
1653 //EgeAdjustmentAction* calligraphy_angle = 0;
1654 EgeAdjustmentAction* eact = 0;
1655 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1656 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1658 /* Flatsided checkbox */
1659 {
1660 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1662 GtkTreeIter iter;
1663 gtk_list_store_append( model, &iter );
1664 gtk_list_store_set( model, &iter,
1665 0, _("Polygon"),
1666 1, _("Regular polygon (with one handle) instead of a star"),
1667 2, "star_flat",
1668 -1 );
1670 gtk_list_store_append( model, &iter );
1671 gtk_list_store_set( model, &iter,
1672 0, _("Star"),
1673 1, _("Star instead of a regular polygon (with one handle)"),
1674 2, "star_angled",
1675 -1 );
1677 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
1678 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1679 g_object_set_data( holder, "flat_action", act );
1681 ege_select_one_action_set_appearance( act, "full" );
1682 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1683 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1684 ege_select_one_action_set_icon_column( act, 2 );
1685 ege_select_one_action_set_tooltip_column( act, 1 );
1687 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1688 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1689 }
1691 /* Magnitude */
1692 //gchar const* labels[] = {_("tri (default)"), _("quad"), _("pent")};
1693 //gdouble values[] = {3, 4, 5};
1694 eact = create_adjustment_action( "MagnitudeAction",
1695 _("Corners:"), _("Number of corners of a polygon or star"),
1696 "tools.shapes.star", "magnitude", 3,
1697 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1698 3, 1024, 1, 5,
1699 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
1700 sp_stb_magnitude_value_changed,
1701 1.0, 0 );
1702 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1703 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1705 /* Spoke ratio */
1706 //gchar const* labels2[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1707 //gdouble values2[] = {-90, 0, 30, 90};
1708 eact = create_adjustment_action( "SpokeAction",
1709 _("Spoke ratio:"),
1710 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1711 // Base radius is the same for the closest handle.
1712 _("Base radius to tip radius ratio"),
1713 "tools.shapes.star", "proportion", 0.5,
1714 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1715 0.01, 1.0, 0.01, 0.1,
1716 0, 0, 0, // labels2, values2, G_N_ELEMENTS(labels2),
1717 sp_stb_proportion_value_changed );
1718 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1719 g_object_set_data( holder, "prop_action", eact );
1721 if ( !isFlatSided ) {
1722 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1723 } else {
1724 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1725 }
1727 /* Roundedness */
1728 //gchar const* labels3[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1729 //gdouble values3[] = {-90, 0, 30, 90};
1730 eact = create_adjustment_action( "RoundednessAction",
1731 _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1732 "tools.shapes.star", "rounded", 0.0,
1733 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1734 -100.0, 100.0, 0.01, 0.1,
1735 0, 0, 0, // labels3, values3, G_N_ELEMENTS(labels3),
1736 sp_stb_rounded_value_changed );
1737 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1738 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1740 /* Randomization */
1741 //gchar const* labels4[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1742 //gdouble values4[] = {-90, 0, 30, 90};
1743 eact = create_adjustment_action( "RandomizationAction",
1744 _("Randomized:"), _("Scatter randomly the corners and angles"),
1745 "tools.shapes.star", "randomized", 0.0,
1746 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1747 -10.0, 10.0, 0.001, 0.01,
1748 0, 0, 0, // labels4, values4, G_N_ELEMENTS(labels4),
1749 sp_stb_randomized_value_changed, 0.1, 3 );
1750 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1751 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1752 }
1754 {
1755 /* Reset */
1756 {
1757 GtkAction* act = gtk_action_new( "StarResetAction",
1758 _("Defaults"),
1759 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1760 GTK_STOCK_CLEAR );
1761 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1762 gtk_action_group_add_action( mainActions, act );
1763 gtk_action_set_sensitive( act, TRUE );
1764 }
1765 }
1767 sigc::connection *connection = new sigc::connection(
1768 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1769 );
1770 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1771 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1772 }
1775 //########################
1776 //## Rect ##
1777 //########################
1779 static void sp_rtb_sensitivize( GObject *tbl )
1780 {
1781 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
1782 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
1783 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
1785 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
1786 gtk_action_set_sensitive( not_rounded, FALSE );
1787 } else {
1788 gtk_action_set_sensitive( not_rounded, TRUE );
1789 }
1790 }
1793 static void
1794 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
1795 void (*setter)(SPRect *, gdouble))
1796 {
1797 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1799 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1800 SPUnit const *unit = tracker->getActiveUnit();
1802 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1803 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1804 }
1806 // quit if run by the attr_changed listener
1807 if (g_object_get_data( tbl, "freeze" )) {
1808 return;
1809 }
1811 // in turn, prevent listener from responding
1812 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1814 bool modmade = false;
1815 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1816 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1817 if (SP_IS_RECT(items->data)) {
1818 if (adj->value != 0) {
1819 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1820 } else {
1821 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1822 }
1823 modmade = true;
1824 }
1825 }
1827 sp_rtb_sensitivize( tbl );
1829 if (modmade) {
1830 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
1831 _("Change rectangle"));
1832 }
1834 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1835 }
1837 static void
1838 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
1839 {
1840 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1841 }
1843 static void
1844 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
1845 {
1846 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1847 }
1849 static void
1850 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
1851 {
1852 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1853 }
1855 static void
1856 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
1857 {
1858 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1859 }
1863 static void
1864 sp_rtb_defaults( GtkWidget *widget, GObject *obj)
1865 {
1866 GtkAdjustment *adj = 0;
1868 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
1869 gtk_adjustment_set_value(adj, 0.0);
1870 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1871 gtk_adjustment_value_changed(adj);
1873 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
1874 gtk_adjustment_set_value(adj, 0.0);
1875 gtk_adjustment_value_changed(adj);
1877 sp_rtb_sensitivize( obj );
1878 }
1880 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1881 gchar const *old_value, gchar const *new_value,
1882 bool is_interactive, gpointer data)
1883 {
1884 GObject *tbl = G_OBJECT(data);
1886 // quit if run by the _changed callbacks
1887 if (g_object_get_data( tbl, "freeze" )) {
1888 return;
1889 }
1891 // in turn, prevent callbacks from responding
1892 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
1894 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1895 SPUnit const *unit = tracker->getActiveUnit();
1897 gpointer item = g_object_get_data( tbl, "item" );
1898 if (item && SP_IS_RECT(item)) {
1899 {
1900 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
1901 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1902 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1903 }
1905 {
1906 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
1907 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1908 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1909 }
1911 {
1912 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
1913 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1914 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1915 }
1917 {
1918 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
1919 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1920 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1921 }
1922 }
1924 sp_rtb_sensitivize( tbl );
1926 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1927 }
1930 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1931 NULL, /* child_added */
1932 NULL, /* child_removed */
1933 rect_tb_event_attr_changed,
1934 NULL, /* content_changed */
1935 NULL /* order_changed */
1936 };
1938 /**
1939 * \param selection should not be NULL.
1940 */
1941 static void
1942 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1943 {
1944 int n_selected = 0;
1945 Inkscape::XML::Node *repr = NULL;
1946 SPItem *item = NULL;
1948 if ( g_object_get_data( tbl, "repr" ) ) {
1949 g_object_set_data( tbl, "item", NULL );
1950 }
1951 purge_repr_listener( tbl, tbl );
1953 for (GSList const *items = selection->itemList();
1954 items != NULL;
1955 items = items->next) {
1956 if (SP_IS_RECT((SPItem *) items->data)) {
1957 n_selected++;
1958 item = (SPItem *) items->data;
1959 repr = SP_OBJECT_REPR(item);
1960 }
1961 }
1963 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1965 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
1967 if (n_selected == 0) {
1968 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1970 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1971 gtk_action_set_sensitive(w, FALSE);
1972 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1973 gtk_action_set_sensitive(h, FALSE);
1975 } else if (n_selected == 1) {
1976 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1977 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
1979 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1980 gtk_action_set_sensitive(w, TRUE);
1981 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1982 gtk_action_set_sensitive(h, TRUE);
1984 if (repr) {
1985 g_object_set_data( tbl, "repr", repr );
1986 g_object_set_data( tbl, "item", item );
1987 Inkscape::GC::anchor(repr);
1988 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1989 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1990 }
1991 } else {
1992 // FIXME: implement averaging of all parameters for multiple selected
1993 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1994 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1995 sp_rtb_sensitivize( tbl );
1996 }
1997 }
2000 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2001 {
2002 EgeAdjustmentAction* eact = 0;
2004 {
2005 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
2006 ege_output_action_set_use_markup( act, TRUE );
2007 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2008 g_object_set_data( holder, "mode_action", act );
2009 }
2011 // rx/ry units menu: create
2012 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
2013 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
2014 // fixme: add % meaning per cent of the width/height
2015 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
2016 g_object_set_data( holder, "tracker", tracker );
2018 /* W */
2019 {
2020 eact = create_adjustment_action( "RectWidthAction",
2021 _("W:"), _("Width of rectangle"),
2022 "tools.shapes.rect", "width", 0,
2023 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
2024 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2025 0, 0, 0,
2026 sp_rtb_width_value_changed );
2027 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2028 g_object_set_data( holder, "width_action", eact );
2029 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2030 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2031 }
2033 /* H */
2034 {
2035 eact = create_adjustment_action( "RectHeightAction",
2036 _("H:"), _("Height of rectangle"),
2037 "tools.shapes.rect", "height", 0,
2038 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2039 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2040 0, 0, 0,
2041 sp_rtb_height_value_changed );
2042 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2043 g_object_set_data( holder, "height_action", eact );
2044 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2045 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2046 }
2048 /* rx */
2049 {
2050 eact = create_adjustment_action( "RadiusXAction",
2051 _("Rx:"), _("Horizontal radius of rounded corners"),
2052 "tools.shapes.rect", "rx", 0,
2053 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2054 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2055 0, 0, 0,
2056 sp_rtb_rx_value_changed);
2057 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2058 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2059 }
2061 /* ry */
2062 {
2063 eact = create_adjustment_action( "RadiusYAction",
2064 _("Ry:"), _("Vertical radius of rounded corners"),
2065 "tools.shapes.rect", "ry", 0,
2066 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2067 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2068 0, 0, 0,
2069 sp_rtb_ry_value_changed);
2070 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2071 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2072 }
2074 // add the units menu
2075 {
2076 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), _("") );
2077 gtk_action_group_add_action( mainActions, act );
2078 }
2080 /* Reset */
2081 {
2082 InkAction* inky = ink_action_new( "RectResetAction",
2083 _("Not rounded"),
2084 _("Make corners sharp"),
2085 "squared_corner",
2086 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2087 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2088 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2089 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2090 g_object_set_data( holder, "not_rounded", inky );
2091 }
2093 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2094 sp_rtb_sensitivize( holder );
2096 sigc::connection *connection = new sigc::connection(
2097 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2098 );
2099 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2100 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2101 }
2103 //########################
2104 //## 3D Box ##
2105 //########################
2107 static void sp_3dbox_toggle_vp_changed( GtkToggleAction *act, gpointer data )
2108 {
2109 guint dir = GPOINTER_TO_UINT(data);
2110 Box3D::PerspDir axis;// = (Box3D::PerspDir) data;
2112 GString *pstring;
2113 switch (dir) {
2114 case 0:
2115 pstring = g_string_new("togglevpx");
2116 axis = Box3D::X;
2117 break;
2118 case 1:
2119 pstring = g_string_new("togglevpy");
2120 axis = Box3D::Y;
2121 break;
2122 case 2:
2123 pstring = g_string_new("togglevpz");
2124 axis = Box3D::Z;
2125 break;
2126 }
2128 if (SP3DBoxContext::current_perspective) {
2129 Box3D::VanishingPoint *vp = SP3DBoxContext::current_perspective->get_vanishing_point(axis);
2130 vp->toggle_parallel();
2131 vp->draw(axis);
2132 prefs_set_int_attribute( "tools.shapes.3dbox", pstring->str, vp->is_finite() ? 0 : 1);
2133 }
2135 }
2137 static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2138 {
2139 bool toggled = false;
2140 /* toggle VP in X direction */
2141 {
2142 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXAction",
2143 _("Toggle VP in X direction"),
2144 _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
2145 "toggle_vp_x",
2146 Inkscape::ICON_SIZE_DECORATION );
2147 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2148 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), (gpointer) 0);
2149 if (SP3DBoxContext::current_perspective) {
2150 toggled = SP3DBoxContext::current_perspective->get_vanishing_point(Box3D::X)->is_finite();
2151 }
2152 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
2153 }
2155 /* toggle VP in Y direction */
2156 {
2157 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYAction",
2158 _("Toggle VP in Y direction"),
2159 _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
2160 "toggle_vp_y",
2161 Inkscape::ICON_SIZE_DECORATION );
2162 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2163 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), (gpointer) 1);
2164 if (SP3DBoxContext::current_perspective) {
2165 toggled = SP3DBoxContext::current_perspective->get_vanishing_point(Box3D::Y)->is_finite();
2166 }
2167 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
2168 }
2170 /* toggle VP in Z direction */
2171 {
2172 InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZAction",
2173 _("Toggle VP in Z direction"),
2174 _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
2175 "toggle_vp_z",
2176 Inkscape::ICON_SIZE_DECORATION );
2177 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2178 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), (gpointer) 2);
2179 if (SP3DBoxContext::current_perspective) {
2180 toggled = SP3DBoxContext::current_perspective->get_vanishing_point(Box3D::Z)->is_finite();
2181 }
2182 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
2183 }
2184 }
2186 //########################
2187 //## Spiral ##
2188 //########################
2190 static void
2191 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2192 {
2193 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2195 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2196 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2197 }
2199 // quit if run by the attr_changed listener
2200 if (g_object_get_data( tbl, "freeze" )) {
2201 return;
2202 }
2204 // in turn, prevent listener from responding
2205 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2207 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2209 bool modmade = false;
2210 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2211 items != NULL;
2212 items = items->next)
2213 {
2214 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2215 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2216 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2217 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2218 modmade = true;
2219 }
2220 }
2222 g_free(namespaced_name);
2224 if (modmade) {
2225 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2226 _("Change spiral"));
2227 }
2229 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2230 }
2232 static void
2233 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2234 {
2235 sp_spl_tb_value_changed(adj, tbl, "revolution");
2236 }
2238 static void
2239 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2240 {
2241 sp_spl_tb_value_changed(adj, tbl, "expansion");
2242 }
2244 static void
2245 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2246 {
2247 sp_spl_tb_value_changed(adj, tbl, "t0");
2248 }
2250 static void
2251 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
2252 {
2253 GtkWidget *tbl = GTK_WIDGET(obj);
2255 GtkAdjustment *adj;
2257 // fixme: make settable
2258 gdouble rev = 5;
2259 gdouble exp = 1.0;
2260 gdouble t0 = 0.0;
2262 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2263 gtk_adjustment_set_value(adj, rev);
2264 gtk_adjustment_value_changed(adj);
2266 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2267 gtk_adjustment_set_value(adj, exp);
2268 gtk_adjustment_value_changed(adj);
2270 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2271 gtk_adjustment_set_value(adj, t0);
2272 gtk_adjustment_value_changed(adj);
2274 spinbutton_defocus(GTK_OBJECT(tbl));
2275 }
2278 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2279 gchar const *old_value, gchar const *new_value,
2280 bool is_interactive, gpointer data)
2281 {
2282 GtkWidget *tbl = GTK_WIDGET(data);
2284 // quit if run by the _changed callbacks
2285 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2286 return;
2287 }
2289 // in turn, prevent callbacks from responding
2290 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2292 GtkAdjustment *adj;
2293 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2294 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2296 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2297 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2299 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2300 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2302 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2303 }
2306 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2307 NULL, /* child_added */
2308 NULL, /* child_removed */
2309 spiral_tb_event_attr_changed,
2310 NULL, /* content_changed */
2311 NULL /* order_changed */
2312 };
2314 static void
2315 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2316 {
2317 int n_selected = 0;
2318 Inkscape::XML::Node *repr = NULL;
2320 purge_repr_listener( tbl, tbl );
2322 for (GSList const *items = selection->itemList();
2323 items != NULL;
2324 items = items->next)
2325 {
2326 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2327 n_selected++;
2328 repr = SP_OBJECT_REPR((SPItem *) items->data);
2329 }
2330 }
2332 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2334 if (n_selected == 0) {
2335 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2336 } else if (n_selected == 1) {
2337 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2339 if (repr) {
2340 g_object_set_data( tbl, "repr", repr );
2341 Inkscape::GC::anchor(repr);
2342 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2343 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2344 }
2345 } else {
2346 // FIXME: implement averaging of all parameters for multiple selected
2347 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2348 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2349 }
2350 }
2353 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2354 {
2355 EgeAdjustmentAction* eact = 0;
2357 {
2358 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2359 ege_output_action_set_use_markup( act, TRUE );
2360 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2361 g_object_set_data( holder, "mode_action", act );
2362 }
2364 /* Revolution */
2365 {
2366 eact = create_adjustment_action( "SpiralRevolutionAction",
2367 _("Turns:"), _("Number of revolutions"),
2368 "tools.shapes.spiral", "revolution", 3.0,
2369 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2370 0.01, 1024.0, 0.1, 1.0,
2371 0, 0, 0,
2372 sp_spl_tb_revolution_value_changed, 1, 2);
2373 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2374 }
2376 /* Expansion */
2377 {
2378 eact = create_adjustment_action( "SpiralExpansionAction",
2379 _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2380 "tools.shapes.spiral", "expansion", 1.0,
2381 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2382 0.0, 1000.0, 0.01, 1.0,
2383 0, 0, 0,
2384 sp_spl_tb_expansion_value_changed);
2385 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2386 }
2388 /* T0 */
2389 {
2390 eact = create_adjustment_action( "SpiralT0Action",
2391 _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2392 "tools.shapes.spiral", "t0", 0.0,
2393 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2394 0.0, 0.999, 0.01, 1.0,
2395 0, 0, 0,
2396 sp_spl_tb_t0_value_changed);
2397 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2398 }
2400 /* Reset */
2401 {
2402 InkAction* inky = ink_action_new( "SpiralResetAction",
2403 _("Defaults"),
2404 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2405 GTK_STOCK_CLEAR,
2406 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2407 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2408 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2409 }
2412 sigc::connection *connection = new sigc::connection(
2413 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2414 );
2415 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2416 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2417 }
2419 //########################
2420 //## Pen/Pencil ##
2421 //########################
2424 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2425 {
2426 // Put stuff here
2427 }
2429 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2430 {
2431 // Put stuff here
2432 }
2435 //########################
2436 //## Calligraphy ##
2437 //########################
2439 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
2440 {
2441 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
2442 }
2444 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
2445 {
2446 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
2447 }
2449 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
2450 {
2451 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
2452 }
2454 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
2455 {
2456 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
2457 }
2459 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
2460 {
2461 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
2462 }
2464 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
2465 {
2466 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
2467 }
2469 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
2470 {
2471 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
2472 }
2474 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
2475 {
2476 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
2477 }
2479 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer data )
2480 {
2481 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2482 }
2484 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer data )
2485 {
2486 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
2487 }
2489 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
2490 {
2491 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2493 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
2494 }
2496 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
2497 {
2498 // FIXME: make defaults settable via Inkscape Options
2499 struct KeyValue {
2500 char const *key;
2501 double value;
2502 } const key_values[] = {
2503 {"mass", 0.02},
2504 {"wiggle", 0.0},
2505 {"angle", 30.0},
2506 {"width", 15},
2507 {"thinning", 0.1},
2508 {"tremor", 0.0},
2509 {"flatness", 0.9},
2510 {"cap_rounding", 0.0}
2511 };
2513 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2514 KeyValue const &kv = key_values[i];
2515 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
2516 if ( adj ) {
2517 gtk_adjustment_set_value(adj, kv.value);
2518 }
2519 }
2520 }
2523 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2524 {
2525 {
2526 EgeAdjustmentAction* calligraphy_angle = 0;
2528 {
2529 /* Width */
2530 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
2531 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2532 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
2533 _("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2534 "tools.calligraphic", "width", 15,
2535 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
2536 1, 100, 1.0, 10.0,
2537 labels, values, G_N_ELEMENTS(labels),
2538 sp_ddc_width_value_changed, 0.01, 0, 100 );
2539 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2540 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2541 }
2543 {
2544 /* Thinning */
2545 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
2546 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
2547 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
2548 _("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2549 "tools.calligraphic", "thinning", 0.1,
2550 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2551 -1.0, 1.0, 0.01, 0.1,
2552 labels, values, G_N_ELEMENTS(labels),
2553 sp_ddc_velthin_value_changed, 0.01, 2);
2554 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2555 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2556 }
2558 {
2559 /* Angle */
2560 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
2561 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2562 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
2563 _("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2564 "tools.calligraphic", "angle", 30,
2565 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
2566 -90.0, 90.0, 1.0, 10.0,
2567 labels, values, G_N_ELEMENTS(labels),
2568 sp_ddc_angle_value_changed, 1, 0 );
2569 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2570 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2571 calligraphy_angle = eact;
2572 }
2574 {
2575 /* Fixation */
2576 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
2577 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
2578 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
2579 _("Fixation:"), _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
2580 "tools.calligraphic", "flatness", 0.9,
2581 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2582 0.0, 1.0, 0.01, 0.1,
2583 labels, values, G_N_ELEMENTS(labels),
2584 sp_ddc_flatness_value_changed, 0.01, 2 );
2585 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2586 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2587 }
2589 {
2590 /* Cap Rounding */
2591 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
2592 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
2593 // TRANSLATORS: "cap" means "end" (both start and finish) here
2594 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
2595 _("Caps:"), _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
2596 "tools.calligraphic", "cap_rounding", 0.0,
2597 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2598 0.0, 5.0, 0.01, 0.1,
2599 labels, values, G_N_ELEMENTS(labels),
2600 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
2601 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2602 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2603 }
2605 {
2606 /* Tremor */
2607 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
2608 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
2609 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
2610 _("Tremor:"), _("Increase to make strokes rugged and trembling"),
2611 "tools.calligraphic", "tremor", 0.0,
2612 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2613 0.0, 1.0, 0.01, 0.1,
2614 labels, values, G_N_ELEMENTS(labels),
2615 sp_ddc_tremor_value_changed, 0.01, 2 );
2617 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2618 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2619 }
2621 {
2622 /* Wiggle */
2623 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
2624 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
2625 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
2626 _("Wiggle:"), _("Increase to make the pen waver and wiggle"),
2627 "tools.calligraphic", "wiggle", 0.0,
2628 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2629 0.0, 1.0, 0.01, 0.1,
2630 labels, values, G_N_ELEMENTS(labels),
2631 sp_ddc_wiggle_value_changed, 0.01, 2 );
2632 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2633 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2634 }
2636 {
2637 /* Mass */
2638 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
2639 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
2640 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
2641 _("Mass:"), _("Increase to make the pen drag behind, as if slowed by inertia"),
2642 "tools.calligraphic", "mass", 0.02,
2643 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2644 0.0, 1.0, 0.01, 0.1,
2645 labels, values, G_N_ELEMENTS(labels),
2646 sp_ddc_mass_value_changed, 0.01, 2 );
2647 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2648 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2649 }
2652 /* Trace Background button */
2653 {
2654 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
2655 _("Trace Background"),
2656 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
2657 "trace_background",
2658 Inkscape::ICON_SIZE_DECORATION );
2659 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2660 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
2661 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
2662 }
2664 /* Use Pressure button */
2665 {
2666 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
2667 _("Pressure"),
2668 _("Use the pressure of the input device to alter the width of the pen"),
2669 "use_pressure",
2670 Inkscape::ICON_SIZE_DECORATION );
2671 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2672 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
2673 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
2674 }
2676 /* Use Tilt button */
2677 {
2678 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
2679 _("Tilt"),
2680 _("Use the tilt of the input device to alter the angle of the pen's nib"),
2681 "use_tilt",
2682 Inkscape::ICON_SIZE_DECORATION );
2683 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2684 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
2685 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2686 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2687 }
2689 /* Reset */
2690 {
2691 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
2692 _("Defaults"),
2693 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2694 GTK_STOCK_CLEAR );
2695 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
2696 gtk_action_group_add_action( mainActions, act );
2697 gtk_action_set_sensitive( act, TRUE );
2698 }
2699 }
2700 }
2703 //########################
2704 //## Circle / Arc ##
2705 //########################
2707 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
2708 {
2709 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
2710 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
2712 if (v1 == 0 && v2 == 0) {
2713 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
2714 gtk_action_set_sensitive( ocb, FALSE );
2715 gtk_action_set_sensitive( make_whole, FALSE );
2716 }
2717 } else {
2718 gtk_action_set_sensitive( ocb, TRUE );
2719 gtk_action_set_sensitive( make_whole, TRUE );
2720 }
2721 }
2723 static void
2724 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
2725 {
2726 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2728 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2729 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2730 }
2732 // quit if run by the attr_changed listener
2733 if (g_object_get_data( tbl, "freeze" )) {
2734 return;
2735 }
2737 // in turn, prevent listener from responding
2738 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2740 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2742 bool modmade = false;
2743 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2744 items != NULL;
2745 items = items->next)
2746 {
2747 SPItem *item = SP_ITEM(items->data);
2749 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2751 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2752 SPArc *arc = SP_ARC(item);
2754 if (!strcmp(value_name, "start"))
2755 ge->start = (adj->value * M_PI)/ 180;
2756 else
2757 ge->end = (adj->value * M_PI)/ 180;
2759 sp_genericellipse_normalize(ge);
2760 ((SPObject *)arc)->updateRepr();
2761 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2763 modmade = true;
2764 }
2765 }
2767 g_free(namespaced_name);
2769 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
2771 sp_arctb_sensitivize( tbl, adj->value, other->value );
2773 if (modmade) {
2774 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
2775 _("Arc: Change start/end"));
2776 }
2778 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2779 }
2782 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
2783 {
2784 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
2785 }
2787 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
2788 {
2789 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
2790 }
2792 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
2793 {
2794 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2795 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2796 if ( ege_select_one_action_get_active( act ) != 0 ) {
2797 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2798 } else {
2799 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2800 }
2801 }
2803 // quit if run by the attr_changed listener
2804 if (g_object_get_data( tbl, "freeze" )) {
2805 return;
2806 }
2808 // in turn, prevent listener from responding
2809 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2811 bool modmade = false;
2813 if ( ege_select_one_action_get_active(act) != 0 ) {
2814 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2815 items != NULL;
2816 items = items->next)
2817 {
2818 if (SP_IS_ARC((SPItem *) items->data)) {
2819 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2820 repr->setAttribute("sodipodi:open", "true");
2821 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2822 modmade = true;
2823 }
2824 }
2825 } else {
2826 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2827 items != NULL;
2828 items = items->next)
2829 {
2830 if (SP_IS_ARC((SPItem *) items->data)) {
2831 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2832 repr->setAttribute("sodipodi:open", NULL);
2833 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2834 modmade = true;
2835 }
2836 }
2837 }
2839 if (modmade) {
2840 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
2841 _("Arc: Change open/closed"));
2842 }
2844 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2845 }
2847 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
2848 {
2849 GtkAdjustment *adj;
2850 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
2851 gtk_adjustment_set_value(adj, 0.0);
2852 gtk_adjustment_value_changed(adj);
2854 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
2855 gtk_adjustment_set_value(adj, 0.0);
2856 gtk_adjustment_value_changed(adj);
2858 spinbutton_defocus( GTK_OBJECT(obj) );
2859 }
2861 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2862 gchar const *old_value, gchar const *new_value,
2863 bool is_interactive, gpointer data)
2864 {
2865 GObject *tbl = G_OBJECT(data);
2867 // quit if run by the _changed callbacks
2868 if (g_object_get_data( tbl, "freeze" )) {
2869 return;
2870 }
2872 // in turn, prevent callbacks from responding
2873 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2875 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2876 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2878 GtkAdjustment *adj1,*adj2;
2879 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
2880 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2881 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
2882 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2884 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
2886 char const *openstr = NULL;
2887 openstr = repr->attribute("sodipodi:open");
2888 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
2890 if (openstr) {
2891 ege_select_one_action_set_active( ocb, 1 );
2892 } else {
2893 ege_select_one_action_set_active( ocb, 0 );
2894 }
2896 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2897 }
2899 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2900 NULL, /* child_added */
2901 NULL, /* child_removed */
2902 arc_tb_event_attr_changed,
2903 NULL, /* content_changed */
2904 NULL /* order_changed */
2905 };
2908 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2909 {
2910 int n_selected = 0;
2911 Inkscape::XML::Node *repr = NULL;
2913 purge_repr_listener( tbl, tbl );
2915 for (GSList const *items = selection->itemList();
2916 items != NULL;
2917 items = items->next)
2918 {
2919 if (SP_IS_ARC((SPItem *) items->data)) {
2920 n_selected++;
2921 repr = SP_OBJECT_REPR((SPItem *) items->data);
2922 }
2923 }
2925 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2927 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2928 if (n_selected == 0) {
2929 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2930 } else if (n_selected == 1) {
2931 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2932 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2934 if (repr) {
2935 g_object_set_data( tbl, "repr", repr );
2936 Inkscape::GC::anchor(repr);
2937 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2938 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2939 }
2940 } else {
2941 // FIXME: implement averaging of all parameters for multiple selected
2942 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2943 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2944 sp_arctb_sensitivize( tbl, 1, 0 );
2945 }
2946 }
2949 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2950 {
2951 EgeAdjustmentAction* eact = 0;
2954 {
2955 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
2956 ege_output_action_set_use_markup( act, TRUE );
2957 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2958 g_object_set_data( holder, "mode_action", act );
2959 }
2961 /* Start */
2962 {
2963 eact = create_adjustment_action( "ArcStartAction",
2964 _("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2965 "tools.shapes.arc", "start", 0.0,
2966 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
2967 -360.0, 360.0, 1.0, 10.0,
2968 0, 0, 0,
2969 sp_arctb_start_value_changed);
2970 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2971 }
2973 /* End */
2974 {
2975 eact = create_adjustment_action( "ArcEndAction",
2976 _("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2977 "tools.shapes.arc", "end", 0.0,
2978 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2979 -360.0, 360.0, 1.0, 10.0,
2980 0, 0, 0,
2981 sp_arctb_end_value_changed);
2982 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2983 }
2985 /* Segments / Pie checkbox */
2986 {
2987 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2989 GtkTreeIter iter;
2990 gtk_list_store_append( model, &iter );
2991 gtk_list_store_set( model, &iter,
2992 0, _("Closed arc"),
2993 1, _("Switch to segment (closed shape with two radii)"),
2994 2, "circle_closed_arc",
2995 -1 );
2997 gtk_list_store_append( model, &iter );
2998 gtk_list_store_set( model, &iter,
2999 0, _("Open Arc"),
3000 1, _("Switch to arc (unclosed shape)"),
3001 2, "circle_open_arc",
3002 -1 );
3004 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
3005 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
3006 g_object_set_data( holder, "open_action", act );
3008 ege_select_one_action_set_appearance( act, "full" );
3009 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
3010 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
3011 ege_select_one_action_set_icon_column( act, 2 );
3012 ege_select_one_action_set_tooltip_column( act, 1 );
3014 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
3015 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
3016 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
3017 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
3018 }
3020 /* Make Whole */
3021 {
3022 InkAction* inky = ink_action_new( "ArcResetAction",
3023 _("Make whole"),
3024 _("Make the shape a whole ellipse, not arc or segment"),
3025 "reset_circle",
3026 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
3027 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
3028 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
3029 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
3030 g_object_set_data( holder, "make_whole", inky );
3031 }
3033 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
3034 // sensitivize make whole and open checkbox
3035 {
3036 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
3037 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
3038 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
3039 }
3042 sigc::connection *connection = new sigc::connection(
3043 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
3044 );
3045 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
3046 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
3047 }
3052 // toggle button callbacks and updaters
3054 //########################
3055 //## Dropper ##
3056 //########################
3058 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
3059 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
3060 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
3061 if ( set_action ) {
3062 if ( gtk_toggle_action_get_active( act ) ) {
3063 gtk_action_set_sensitive( set_action, TRUE );
3064 } else {
3065 gtk_action_set_sensitive( set_action, FALSE );
3066 }
3067 }
3069 spinbutton_defocus(GTK_OBJECT(tbl));
3070 }
3072 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
3073 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
3074 spinbutton_defocus(GTK_OBJECT(tbl));
3075 }
3078 /**
3079 * Dropper auxiliary toolbar construction and setup.
3080 *
3081 * TODO: Would like to add swatch of current color.
3082 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3083 * can drag and drop places. Will provide a nice mixing palette.
3084 */
3085 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
3086 {
3087 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
3089 {
3090 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
3091 _("Pick alpha"),
3092 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
3093 "color_alpha_get",
3094 Inkscape::ICON_SIZE_DECORATION );
3095 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3096 g_object_set_data( holder, "pick_action", act );
3097 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
3098 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
3099 }
3101 {
3102 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
3103 _("Set alpha"),
3104 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
3105 "color_alpha_set",
3106 Inkscape::ICON_SIZE_DECORATION );
3107 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
3108 g_object_set_data( holder, "set_action", act );
3109 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
3110 // make sure it's disabled if we're not picking alpha
3111 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
3112 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
3113 }
3114 }
3117 //########################
3118 //## Text Toolbox ##
3119 //########################
3120 /*
3121 static void
3122 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3123 {
3124 //Call back for letter sizing spinbutton
3125 }
3127 static void
3128 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3129 {
3130 //Call back for line height spinbutton
3131 }
3133 static void
3134 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3135 {
3136 //Call back for horizontal kerning spinbutton
3137 }
3139 static void
3140 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3141 {
3142 //Call back for vertical kerning spinbutton
3143 }
3145 static void
3146 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3147 {
3148 //Call back for letter rotation spinbutton
3149 }*/
3151 namespace {
3153 bool visible = false;
3155 void
3156 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
3157 {
3159 SPStyle *query =
3160 sp_style_new ();
3162 int result_family =
3163 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3165 int result_style =
3166 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3168 int result_numbers =
3169 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3171 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3173 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3174 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3175 {
3176 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3178 if (repr)
3179 {
3180 sp_style_read_from_repr (query, repr);
3181 }
3182 else
3183 {
3184 return;
3185 }
3186 }
3188 if (query->text)
3189 {
3190 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3191 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3192 gtk_entry_set_text (GTK_ENTRY (entry), "");
3194 } else if (query->text->font_family.value) {
3196 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3197 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3199 Gtk::TreePath path;
3200 try {
3201 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3202 } catch (...) {
3203 return;
3204 }
3206 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3207 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3209 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3211 gtk_tree_selection_select_path (tselection, path.gobj());
3212 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3214 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3215 }
3217 //Size
3218 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3219 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3220 g_object_set_data (tbl, "size-block", gpointer(1));
3221 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3222 g_object_set_data (tbl, "size-block", gpointer(0));
3223 free (str);
3225 //Anchor
3226 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3227 {
3228 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3229 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3230 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3231 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3232 }
3233 else
3234 {
3235 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3236 {
3237 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3238 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3239 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3240 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3241 }
3242 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3243 {
3244 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3245 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3246 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3247 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3248 }
3249 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3250 {
3251 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3252 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3253 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3254 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3255 }
3256 }
3258 //Style
3259 {
3260 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3262 gboolean active = gtk_toggle_button_get_active (button);
3263 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3265 if (active != check)
3266 {
3267 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3268 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3269 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3270 }
3271 }
3273 {
3274 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3276 gboolean active = gtk_toggle_button_get_active (button);
3277 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3279 if (active != check)
3280 {
3281 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3282 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3283 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3284 }
3285 }
3287 //Orientation
3288 //locking both buttons, changing one affect all group (both)
3289 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3290 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3292 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3293 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3295 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3296 {
3297 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3298 }
3299 else
3300 {
3301 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3302 }
3303 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3304 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3305 }
3306 }
3308 void
3309 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
3310 {
3311 sp_text_toolbox_selection_changed (selection, tbl);
3312 }
3314 void
3315 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3316 {
3317 sp_text_toolbox_selection_changed (NULL, tbl);
3318 }
3320 void
3321 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
3322 GObject *tbl)
3323 {
3324 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3325 GtkTreeModel *model = 0;
3326 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3327 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3328 GtkTreeIter iter;
3329 char *family = 0;
3331 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3332 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3334 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3335 return;
3336 }
3338 gtk_tree_model_get (model, &iter, 0, &family, -1);
3340 if (g_object_get_data (G_OBJECT (selection), "block"))
3341 {
3342 gtk_entry_set_text (GTK_ENTRY (entry), family);
3343 return;
3344 }
3346 gtk_widget_hide (popdown);
3347 visible = false;
3349 gtk_entry_set_text (GTK_ENTRY (entry), family);
3351 SPStyle *query =
3352 sp_style_new ();
3354 int result_numbers =
3355 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3357 SPCSSAttr *css = sp_repr_css_attr_new ();
3358 sp_repr_css_set_property (css, "font-family", family);
3360 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3361 if (result_numbers == QUERY_STYLE_NOTHING)
3362 {
3363 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3364 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3365 }
3366 else
3367 {
3368 sp_desktop_set_style (desktop, css, true, true);
3369 }
3371 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3372 _("Text: Change font family"));
3373 sp_repr_css_attr_unref (css);
3374 free (family);
3375 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3377 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3378 }
3380 void
3381 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
3382 GObject *tbl)
3383 {
3384 const char *family = gtk_entry_get_text (entry);
3386 try {
3387 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3388 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3389 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3390 gtk_tree_selection_select_path (selection, path.gobj());
3391 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3392 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3393 } catch (...) {
3394 if (family && strlen (family))
3395 {
3396 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3397 }
3398 }
3399 }
3401 void
3402 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
3403 gpointer data)
3404 {
3405 if (g_object_get_data (G_OBJECT (button), "block")) return;
3406 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3407 int prop = GPOINTER_TO_INT(data);
3409 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3410 SPCSSAttr *css = sp_repr_css_attr_new ();
3412 switch (prop)
3413 {
3414 case 0:
3415 {
3416 sp_repr_css_set_property (css, "text-anchor", "start");
3417 sp_repr_css_set_property (css, "text-align", "start");
3418 break;
3419 }
3420 case 1:
3421 {
3422 sp_repr_css_set_property (css, "text-anchor", "middle");
3423 sp_repr_css_set_property (css, "text-align", "center");
3424 break;
3425 }
3427 case 2:
3428 {
3429 sp_repr_css_set_property (css, "text-anchor", "end");
3430 sp_repr_css_set_property (css, "text-align", "end");
3431 break;
3432 }
3434 case 3:
3435 {
3436 sp_repr_css_set_property (css, "text-anchor", "start");
3437 sp_repr_css_set_property (css, "text-align", "justify");
3438 break;
3439 }
3440 }
3442 SPStyle *query =
3443 sp_style_new ();
3444 int result_numbers =
3445 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3447 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3448 if (result_numbers == QUERY_STYLE_NOTHING)
3449 {
3450 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3451 }
3453 sp_desktop_set_style (desktop, css, true, true);
3454 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3455 _("Text: Change alignment"));
3456 sp_repr_css_attr_unref (css);
3458 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3459 }
3461 void
3462 sp_text_toolbox_style_toggled (GtkToggleButton *button,
3463 gpointer data)
3464 {
3465 if (g_object_get_data (G_OBJECT (button), "block")) return;
3467 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3468 SPCSSAttr *css = sp_repr_css_attr_new ();
3469 int prop = GPOINTER_TO_INT(data);
3470 bool active = gtk_toggle_button_get_active (button);
3473 switch (prop)
3474 {
3475 case 0:
3476 {
3477 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
3478 break;
3479 }
3481 case 1:
3482 {
3483 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
3484 break;
3485 }
3486 }
3488 SPStyle *query =
3489 sp_style_new ();
3490 int result_numbers =
3491 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3493 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3494 if (result_numbers == QUERY_STYLE_NOTHING)
3495 {
3496 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3497 }
3499 sp_desktop_set_style (desktop, css, true, true);
3500 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3501 _("Text: Change font style"));
3502 sp_repr_css_attr_unref (css);
3504 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3505 }
3507 void
3508 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
3509 gpointer data)
3510 {
3511 if (g_object_get_data (G_OBJECT (button), "block")) {
3512 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3513 return;
3514 }
3516 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3517 SPCSSAttr *css = sp_repr_css_attr_new ();
3518 int prop = GPOINTER_TO_INT(data);
3520 switch (prop)
3521 {
3522 case 0:
3523 {
3524 sp_repr_css_set_property (css, "writing-mode", "lr");
3525 break;
3526 }
3528 case 1:
3529 {
3530 sp_repr_css_set_property (css, "writing-mode", "tb");
3531 break;
3532 }
3533 }
3535 SPStyle *query =
3536 sp_style_new ();
3537 int result_numbers =
3538 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3540 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3541 if (result_numbers == QUERY_STYLE_NOTHING)
3542 {
3543 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3544 }
3546 sp_desktop_set_style (desktop, css, true, true);
3547 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3548 _("Text: Change orientation"));
3549 sp_repr_css_attr_unref (css);
3551 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3552 }
3554 gboolean
3555 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3556 {
3557 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3558 if (!desktop) return FALSE;
3560 switch (get_group0_keyval (event)) {
3561 case GDK_Escape: // defocus
3562 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3563 return TRUE; // I consumed the event
3564 break;
3565 case GDK_Return: // defocus
3566 case GDK_KP_Enter:
3567 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3568 return TRUE; // I consumed the event
3569 break;
3570 }
3571 return FALSE;
3572 }
3574 gboolean
3575 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3576 {
3577 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3578 if (!desktop) return FALSE;
3580 switch (get_group0_keyval (event)) {
3581 case GDK_Escape: // defocus
3582 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3583 sp_text_toolbox_selection_changed (NULL, tbl); // update
3584 return TRUE; // I consumed the event
3585 break;
3586 }
3587 return FALSE;
3588 }
3590 gboolean
3591 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3592 {
3593 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3594 if (!desktop) return FALSE;
3596 switch (get_group0_keyval (event)) {
3597 case GDK_Escape: // defocus
3598 gtk_widget_hide (w);
3599 visible = false;
3600 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3601 return TRUE; // I consumed the event
3602 break;
3603 }
3604 return FALSE;
3605 }
3608 void
3609 sp_text_toolbox_size_changed (GtkComboBox *cbox,
3610 GObject *tbl)
3611 {
3612 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3614 if (g_object_get_data (tbl, "size-block")) return;
3616 #if GTK_CHECK_VERSION(2,6,0)
3617 char *text = gtk_combo_box_get_active_text (cbox);
3618 #else // GTK_CHECK_VERSION(2,6,0)
3619 GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3620 GtkTreeIter iter;
3621 char *text = NULL;
3623 if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3624 gtk_tree_model_get (model, &iter, 0, &text, -1);
3625 #endif // GTK_CHECK_VERSION(2,6,0)
3627 SPCSSAttr *css = sp_repr_css_attr_new ();
3628 sp_repr_css_set_property (css, "font-size", text);
3629 free (text);
3631 SPStyle *query =
3632 sp_style_new ();
3633 int result_numbers =
3634 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3636 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3637 if (result_numbers == QUERY_STYLE_NOTHING)
3638 {
3639 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3640 }
3642 sp_desktop_set_style (desktop, css, true, true);
3643 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
3644 _("Text: Change font size"));
3645 sp_repr_css_attr_unref (css);
3648 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3649 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3650 }
3652 void
3653 sp_text_toolbox_text_popdown_clicked (GtkButton *button,
3654 GObject *tbl)
3655 {
3656 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3657 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3658 int x, y;
3660 if (!visible)
3661 {
3662 gdk_window_get_origin (widget->window, &x, &y);
3663 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
3664 gtk_widget_show_all (popdown);
3666 gdk_pointer_grab (widget->window, TRUE,
3667 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3668 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3669 GDK_POINTER_MOTION_MASK),
3670 NULL, NULL, GDK_CURRENT_TIME);
3672 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3674 visible = true;
3675 }
3676 else
3677 {
3678 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3679 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3680 gtk_widget_hide (popdown);
3681 visible = false;
3682 }
3683 }
3685 gboolean
3686 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
3687 GdkEventFocus *event,
3688 GObject *tbl)
3689 {
3690 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3691 return FALSE;
3692 }
3694 gboolean
3695 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
3696 GdkEventFocus *event,
3697 GObject *tbl)
3698 {
3699 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3701 gtk_widget_hide (popdown);
3702 visible = false;
3703 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3704 return TRUE;
3705 }
3707 void
3708 cell_data_func (GtkTreeViewColumn *column,
3709 GtkCellRenderer *cell,
3710 GtkTreeModel *tree_model,
3711 GtkTreeIter *iter,
3712 gpointer data)
3713 {
3714 char *family,
3715 *family_escaped,
3716 *sample_escaped;
3718 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3720 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3722 family_escaped = g_markup_escape_text (family, -1);
3723 sample_escaped = g_markup_escape_text (sample, -1);
3725 std::stringstream markup;
3726 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3727 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3729 free (family);
3730 free (family_escaped);
3731 free (sample_escaped);
3732 }
3734 static void delete_completion(GObject *obj, GtkWidget *entry) {
3735 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3736 if (completion) {
3737 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3738 g_object_unref (completion);
3739 }
3740 }
3742 GtkWidget*
3743 sp_text_toolbox_new (SPDesktop *desktop)
3744 {
3745 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
3747 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3748 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3750 GtkTooltips *tt = gtk_tooltips_new();
3751 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3753 ////////////Family
3754 //Window
3755 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3756 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3758 //Entry
3759 GtkWidget *entry = gtk_entry_new ();
3760 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3761 GtkEntryCompletion *completion = gtk_entry_completion_new ();
3762 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3763 gtk_entry_completion_set_text_column (completion, 0);
3764 gtk_entry_completion_set_minimum_key_length (completion, 1);
3765 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3766 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3767 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
3768 aux_toolbox_space (tbl, 1);
3769 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3770 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
3772 //Button
3773 GtkWidget *button = gtk_button_new ();
3774 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3775 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3777 //Popdown
3778 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
3779 GtkWidget *treeview = gtk_tree_view_new ();
3781 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
3782 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
3783 gtk_tree_view_column_pack_start (column, cell, FALSE);
3784 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3785 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3786 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3788 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3789 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3790 #if GTK_CHECK_VERSION(2,6,0)
3791 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3792 #endif // GTK_CHECK_VERSION(2,6,0)
3794 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3796 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
3797 gtk_container_add (GTK_CONTAINER (sw), treeview);
3799 gtk_container_add (GTK_CONTAINER (window), sw);
3800 gtk_widget_set_size_request (window, 300, 450);
3802 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3803 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3804 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3806 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3808 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3809 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3811 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3812 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3814 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3815 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3816 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3817 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3818 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3820 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3821 aux_toolbox_space (tbl, 1);
3822 GtkWidget *box = gtk_event_box_new ();
3823 gtk_container_add (GTK_CONTAINER (box), image);
3824 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3825 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3826 GtkTooltips *tooltips = gtk_tooltips_new ();
3827 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3828 gtk_widget_hide (GTK_WIDGET (box));
3829 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3831 ////////////Size
3832 const char *sizes[] = {
3833 "4", "6", "8", "9", "10", "11", "12", "13", "14",
3834 "16", "18", "20", "22", "24", "28",
3835 "32", "36", "40", "48", "56", "64", "72", "144"
3836 };
3838 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3839 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3840 gtk_widget_set_size_request (cbox, 80, -1);
3841 aux_toolbox_space (tbl, 1);
3842 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3843 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3844 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3845 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3847 //spacer
3848 aux_toolbox_space (tbl, 4);
3849 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3851 ////////////Text anchor
3852 GtkWidget *group = gtk_radio_button_new (NULL);
3853 GtkWidget *row = gtk_hbox_new (FALSE, 4);
3854 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3856 // left
3857 GtkWidget *rbutton = group;
3858 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3859 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3860 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3862 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3863 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
3864 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3865 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3867 // center
3868 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3869 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3870 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3871 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3873 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3874 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
3875 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
3876 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3878 // right
3879 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3880 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3881 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3882 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3884 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3885 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
3886 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3887 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3889 // fill
3890 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3891 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3892 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3893 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3895 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3896 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
3897 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3898 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3900 aux_toolbox_space (tbl, 1);
3901 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3903 //spacer
3904 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3906 ////////////Text style
3907 row = gtk_hbox_new (FALSE, 4);
3909 // bold
3910 rbutton = gtk_toggle_button_new ();
3911 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3912 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3913 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3914 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3916 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3917 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
3918 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3920 // italic
3921 rbutton = gtk_toggle_button_new ();
3922 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3923 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3924 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3925 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3927 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3928 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
3929 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
3931 aux_toolbox_space (tbl, 1);
3932 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3934 //spacer
3935 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3937 ////////////Text orientation
3938 group = gtk_radio_button_new (NULL);
3939 row = gtk_hbox_new (FALSE, 4);
3940 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3942 // horizontal
3943 rbutton = group;
3944 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3945 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
3946 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3947 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3949 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3950 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3951 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3953 // vertical
3954 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3955 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3956 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
3957 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3958 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3960 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3961 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
3962 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
3963 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3966 //watch selection
3967 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3969 sigc::connection *c_selection_changed =
3970 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
3971 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3972 pool->add_connection ("selection-changed", c_selection_changed);
3974 sigc::connection *c_selection_modified =
3975 new sigc::connection (sp_desktop_selection (desktop)->connectModified
3976 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3977 pool->add_connection ("selection-modified", c_selection_modified);
3979 sigc::connection *c_subselection_changed =
3980 new sigc::connection (desktop->connectToolSubselectionChanged
3981 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3982 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3984 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3987 #if 0
3988 // horizontal
3989 {
3990 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3991 GtkWidget *b = group = gtk_radio_button_new (NULL);
3992 gtk_container_add (GTK_CONTAINER (b), px);
3993 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3994 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3995 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3996 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3997 }
3999 // vertical
4000 {
4001 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
4002 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4003 gtk_container_add (GTK_CONTAINER (b), px);
4004 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
4005 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4006 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4007 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4008 }
4010 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4012 // letter spacing
4013 {
4014 {
4015 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
4016 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4017 gtk_container_add (GTK_CONTAINER (hb), image);
4018 gtk_widget_show(image);
4019 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4020 }
4022 {
4023 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
4024 "tools.text", "letter_spacing", 0.0,
4025 us, tbl, FALSE, NULL,
4026 -1000.0, 1000.0, 0.1, 0.1,
4027 sp_text_letter_changed, 0.1, 1);
4028 gtk_widget_set_size_request (hb, 45, 6);
4029 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4030 }
4031 }
4033 // line spacing
4034 {
4035 {
4036 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
4037 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4038 gtk_container_add (GTK_CONTAINER (hb), image);
4039 gtk_widget_show(image);
4040 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4041 }
4043 {
4044 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
4045 "tools.text", "line_spacing", 0,
4046 us, tbl, FALSE, NULL,
4047 -1000.0, 1000.0, 0.1, 0.1,
4048 sp_text_line_changed, 0.1, 1);
4049 gtk_widget_set_size_request (hb, 45, 0);
4050 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
4051 }
4052 }
4054 {
4055 // horizontal kerning/vertical kerning units menu: create
4056 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
4057 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
4058 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
4060 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4062 // horizontal kerning
4063 {
4064 {
4065 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
4066 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4067 gtk_container_add (GTK_CONTAINER (hb), image);
4068 gtk_widget_show(image);
4069 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4070 }
4072 {
4073 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
4074 "tools.text", "horizontal_kerning", 0,
4075 us, tbl, FALSE, NULL,
4076 -100.00, 100.00, 0.01, 0.1,
4077 sp_text_horiz_kern_changed);
4078 gtk_widget_set_size_request (hb, 45, 0);
4079 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4080 }
4081 }
4083 // vertical kerning
4084 {
4085 {
4086 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
4087 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4088 gtk_container_add (GTK_CONTAINER (hb), image);
4089 gtk_widget_show(image);
4090 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4091 }
4093 {
4094 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
4095 "tools.text", "vertical_kerning", 0,
4096 us, tbl, FALSE, NULL,
4097 -100.00, 100.00, 0.01, 0.1,
4098 sp_text_vert_kern_changed);
4099 gtk_widget_set_size_request (hb, 45, 0);
4100 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
4101 }
4102 }
4104 // add the units menu
4105 gtk_widget_show(us);
4106 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
4107 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
4108 }
4110 // letter rotation
4111 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4112 {
4113 {
4114 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
4115 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4116 gtk_container_add (GTK_CONTAINER (hb), image);
4117 gtk_widget_show(image);
4118 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4119 }
4120 {
4121 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
4122 "tools.text", "letter_rotation", 0,
4123 us, tbl, FALSE, NULL,
4124 -180.0, 180.0, 0.1, 0.1,
4125 sp_text_letter_rotation_changed, 0.1, 1);
4126 gtk_widget_set_size_request (hb, 45, 0);
4127 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4128 }
4129 // rotation degree label
4130 {
4131 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4132 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4133 }
4134 }
4136 // Remove Manual Kerns
4137 {
4138 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4139 GtkWidget *button = gtk_button_new ();
4140 gtk_container_add (GTK_CONTAINER (button), px);
4141 gtk_widget_show(button);
4142 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4143 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4144 gtk_widget_set_sensitive(button, TRUE);
4145 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4146 }
4147 #endif
4149 gtk_widget_show_all (tbl);
4150 return tbl;
4152 } // end of sp_text_toolbox_new()
4154 }//<unnamed> namespace
4157 //#########################
4158 //## Connector Toolbox ##
4159 //#########################
4161 static void sp_connector_path_set_avoid(void)
4162 {
4163 cc_selection_set_avoid(true);
4164 }
4167 static void sp_connector_path_set_ignore(void)
4168 {
4169 cc_selection_set_avoid(false);
4170 }
4174 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4175 {
4176 // quit if run by the _changed callbacks
4177 if (g_object_get_data( tbl, "freeze" )) {
4178 return;
4179 }
4181 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4182 SPDocument *doc = sp_desktop_document(desktop);
4184 if (!sp_document_get_undo_sensitive(doc))
4185 {
4186 return;
4187 }
4189 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4191 if ( repr->attribute("inkscape:connector-spacing") ) {
4192 gdouble priorValue = gtk_adjustment_get_value(adj);
4193 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4194 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4195 return;
4196 }
4197 } else if ( adj->value == defaultConnSpacing ) {
4198 return;
4199 }
4201 // in turn, prevent callbacks from responding
4202 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4204 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4205 SP_OBJECT(desktop->namedview)->updateRepr();
4207 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4208 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4209 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4210 NR::Matrix m = NR::identity();
4211 avoid_item_move(&m, item);
4212 }
4214 if (items) {
4215 g_slist_free(items);
4216 }
4218 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4219 _("Change connector spacing"));
4221 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4223 spinbutton_defocus(GTK_OBJECT(tbl));
4224 }
4226 static void sp_connector_graph_layout(void)
4227 {
4228 if (!SP_ACTIVE_DESKTOP) return;
4230 // hack for clones, see comment in align-and-distribute.cpp
4231 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4232 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4234 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4236 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4238 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4239 }
4241 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject *tbl )
4242 {
4243 if ( gtk_toggle_action_get_active( act ) ) {
4244 prefs_set_string_attribute("tools.connector", "directedlayout",
4245 "true");
4246 } else {
4247 prefs_set_string_attribute("tools.connector", "directedlayout",
4248 "false");
4249 }
4250 }
4252 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject *tbl )
4253 {
4254 if ( gtk_toggle_action_get_active( act ) ) {
4255 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4256 "true");
4257 } else {
4258 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4259 "false");
4260 }
4261 }
4264 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4265 {
4266 prefs_set_double_attribute("tools.connector", "length", adj->value);
4267 spinbutton_defocus(GTK_OBJECT(tbl));
4268 }
4270 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4271 gchar const *name, gchar const *old_value, gchar const *new_value,
4272 bool is_interactive, gpointer data)
4273 {
4274 GtkWidget *tbl = GTK_WIDGET(data);
4276 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4277 return;
4278 }
4279 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4280 return;
4281 }
4283 GtkAdjustment *adj = (GtkAdjustment*)
4284 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4285 gdouble spacing = defaultConnSpacing;
4286 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4288 gtk_adjustment_set_value(adj, spacing);
4289 }
4292 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4293 NULL, /* child_added */
4294 NULL, /* child_removed */
4295 connector_tb_event_attr_changed,
4296 NULL, /* content_changed */
4297 NULL /* order_changed */
4298 };
4301 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
4302 {
4303 {
4304 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
4305 _("Avoid"),
4306 _("Make connectors avoid selected objects"),
4307 "connector_avoid",
4308 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4309 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
4310 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4311 }
4313 {
4314 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
4315 _("Ignore"),
4316 _("Make connectors ignore selected objects"),
4317 "connector_ignore",
4318 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4319 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
4320 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4321 }
4323 EgeAdjustmentAction* eact = 0;
4325 // Spacing spinbox
4326 eact = create_adjustment_action( "ConnectorSpacingAction",
4327 _("Spacing:"), _("The amount of space left around objects by auto-routing connectors"),
4328 "tools.connector", "spacing", defaultConnSpacing,
4329 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
4330 0, 100, 1.0, 10.0,
4331 0, 0, 0,
4332 connector_spacing_changed, 1, 0 );
4333 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4335 // Graph (connector network) layout
4336 {
4337 InkAction* inky = ink_action_new( "ConnectorGraphAction",
4338 _("Graph"),
4339 _("Nicely arrange selected connector network"),
4340 "graph_layout",
4341 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4342 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
4343 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4344 }
4346 // Default connector length spinbox
4347 eact = create_adjustment_action( "ConnectorLengthAction",
4348 _("Length:"), _("Ideal length for connectors when layout is applied"),
4349 "tools.connector", "length", 100,
4350 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
4351 10, 1000, 10.0, 100.0,
4352 0, 0, 0,
4353 connector_length_changed, 1, 0 );
4354 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4357 // Directed edges toggle button
4358 {
4359 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
4360 _("Downwards"),
4361 _("Make connectors with end-markers (arrows) point downwards"),
4362 "directed_graph",
4363 Inkscape::ICON_SIZE_DECORATION );
4364 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4366 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
4367 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4368 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4370 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
4371 }
4373 // Avoid overlaps toggle button
4374 {
4375 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
4376 _("Remove overlaps"),
4377 _("Do not allow overlapping shapes"),
4378 "remove_overlaps",
4379 Inkscape::ICON_SIZE_DECORATION );
4380 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4382 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
4383 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4384 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4386 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
4387 }
4389 // Code to watch for changes to the connector-spacing attribute in
4390 // the XML.
4391 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4392 g_assert(repr != NULL);
4394 purge_repr_listener( holder, holder );
4396 if (repr) {
4397 g_object_set_data( holder, "repr", repr );
4398 Inkscape::GC::anchor(repr);
4399 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
4400 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
4401 }
4402 } // end of sp_connector_toolbox_prep()
4404 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* tbl)
4405 {
4406 gint channels = ege_select_one_action_get_active( act );
4407 flood_channels_set_channels( channels );
4408 }
4410 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject *tbl)
4411 {
4412 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4413 }
4415 static void paintbucket_autogap_changed(EgeSelectOneAction* act, GObject *tbl)
4416 {
4417 prefs_set_int_attribute("tools.paintbucket", "autogap", ege_select_one_action_get_active( act ));
4418 }
4420 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
4421 {
4422 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
4423 SPUnit const *unit = tracker->getActiveUnit();
4426 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
4427 }
4429 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
4430 {
4431 // FIXME: make defaults settable via Inkscape Options
4432 struct KeyValue {
4433 char const *key;
4434 double value;
4435 } const key_values[] = {
4436 {"threshold", 15},
4437 {"offset", 0.0}
4438 };
4440 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
4441 KeyValue const &kv = key_values[i];
4442 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
4443 if ( adj ) {
4444 gtk_adjustment_set_value(adj, kv.value);
4445 }
4446 }
4448 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
4449 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
4450 EgeSelectOneAction* autogap_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "autogap_action" ) );
4451 ege_select_one_action_set_active( autogap_action, 0 );
4452 }
4454 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4455 {
4456 EgeAdjustmentAction* eact = 0;
4458 {
4459 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4461 GList* items = 0;
4462 gint count = 0;
4463 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
4464 {
4465 GtkTreeIter iter;
4466 gtk_list_store_append( model, &iter );
4467 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4468 count++;
4469 }
4470 g_list_free( items );
4471 items = 0;
4472 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by:"), _(""), NULL, GTK_TREE_MODEL(model) );
4473 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
4474 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
4475 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
4476 g_object_set_data( holder, "channels_action", act1 );
4477 }
4479 // Spacing spinbox
4480 {
4481 eact = create_adjustment_action(
4482 "ThresholdAction",
4483 _("Threshold:"),
4484 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
4485 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
4486 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
4487 0, 0, 0,
4488 paintbucket_threshold_changed, 1, 0 );
4490 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4491 }
4493 // Create the units menu.
4494 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
4495 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
4496 g_object_set_data( holder, "tracker", tracker );
4497 {
4498 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), _("") );
4499 gtk_action_group_add_action( mainActions, act );
4500 }
4502 // Offset spinbox
4503 {
4504 eact = create_adjustment_action(
4505 "OffsetAction",
4506 _("Grow/shrink by:"),
4507 _("The amount to grow (positive) or shrink (negative) the created fill path"),
4508 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
4509 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
4510 0, 0, 0,
4511 paintbucket_offset_changed, 1, 2);
4512 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
4514 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4515 }
4517 /* Auto Gap */
4518 {
4519 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4521 GList* items = 0;
4522 gint count = 0;
4523 for ( items = flood_autogap_dropdown_items_list(); items ; items = g_list_next(items) )
4524 {
4525 GtkTreeIter iter;
4526 gtk_list_store_append( model, &iter );
4527 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4528 count++;
4529 }
4530 g_list_free( items );
4531 items = 0;
4532 EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Fill gaps:"), _(""), NULL, GTK_TREE_MODEL(model) );
4533 ege_select_one_action_set_active( act2, prefs_get_int_attribute("tools.paintbucket", "autogap", 0) );
4534 g_signal_connect( G_OBJECT(act2), "changed", G_CALLBACK(paintbucket_autogap_changed), holder );
4535 gtk_action_group_add_action( mainActions, GTK_ACTION(act2) );
4536 g_object_set_data( holder, "autogap_action", act2 );
4537 }
4539 /* Reset */
4540 {
4541 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
4542 _("Defaults"),
4543 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
4544 GTK_STOCK_CLEAR );
4545 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
4546 gtk_action_group_add_action( mainActions, act );
4547 gtk_action_set_sensitive( act, TRUE );
4548 }
4550 }
4552 /*
4553 Local Variables:
4554 mode:c++
4555 c-file-style:"stroustrup"
4556 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4557 indent-tabs-mode:nil
4558 fill-column:99
4559 End:
4560 */
4561 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :