dad4f11f6a3a61dfea4dd6df13e219374ce81c4c
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 "nodepath.h"
51 #include "xml/repr.h"
52 #include "xml/node-event-vector.h"
53 #include <glibmm/i18n.h>
54 #include "helper/unit-menu.h"
55 #include "helper/units.h"
57 #include "inkscape.h"
58 #include "conn-avoid-ref.h"
61 #include "select-toolbar.h"
62 #include "gradient-toolbar.h"
64 #include "connector-context.h"
65 #include "sp-rect.h"
66 #include "sp-star.h"
67 #include "sp-spiral.h"
68 #include "sp-ellipse.h"
69 #include "sp-text.h"
70 #include "sp-flowtext.h"
71 #include "style.h"
72 #include "selection.h"
73 #include "document-private.h"
74 #include "desktop-style.h"
75 #include "../libnrtype/font-lister.h"
76 #include "../connection-pool.h"
77 #include "../prefs-utils.h"
78 #include "../inkscape-stock.h"
79 #include "icon.h"
80 #include "graphlayout/graphlayout.h"
82 #include "mod360.h"
84 #include "toolbox.h"
86 #include "flood-context.h"
88 #include "ink-action.h"
89 #include "ege-adjustment-action.h"
90 #include "ege-output-action.h"
91 #include "ege-select-one-action.h"
92 #include "helper/unit-tracker.h"
94 using Inkscape::UnitTracker;
96 typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop);
97 typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
99 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
100 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
101 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
102 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
103 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
104 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
105 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
106 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
107 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
108 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
109 static GtkWidget *sp_empty_toolbox_new(SPDesktop *desktop);
110 static void sp_connector_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
111 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
113 namespace { GtkWidget *sp_text_toolbox_new (SPDesktop *desktop); }
116 static struct {
117 gchar const *type_name;
118 gchar const *data_name;
119 sp_verb_t verb;
120 sp_verb_t doubleclick_verb;
121 } const tools[] = {
122 { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS},
123 { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
124 { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
125 { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
126 { "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
127 { "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
128 { "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
129 { "SPPencilContext", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS },
130 { "SPPenContext", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS },
131 { "SPDynaDrawContext", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
132 { "SPFloodContext", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
133 { "SPTextContext", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
134 { "SPConnectorContext","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
135 { "SPGradientContext", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
136 { "SPDropperContext", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS },
137 { NULL, NULL, 0, 0 }
138 };
140 static struct {
141 gchar const *type_name;
142 gchar const *data_name;
143 GtkWidget *(*create_func)(SPDesktop *desktop);
144 void (*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
145 gchar const *ui_name;
146 gint swatch_verb_id;
147 gchar const *swatch_tool;
148 gchar const *swatch_tip;
149 } const aux_toolboxes[] = {
150 { "SPSelectContext", "select_toolbox", 0, sp_select_toolbox_prep, "SelectToolbar",
151 SP_VERB_INVALID, 0, 0},
152 { "SPNodeContext", "node_toolbox", 0, sp_node_toolbox_prep, "NodeToolbar",
153 SP_VERB_INVALID, 0, 0},
154 { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar",
155 SP_VERB_INVALID, 0, 0},
156 { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar",
157 SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
158 { "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
159 SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
160 { "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
161 SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
162 { "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
163 SP_VERB_CONTEXT_SPIRAL_PREFS, "tools.shapes.spiral", _("Style of new spirals")},
164 { "SPPencilContext", "pencil_toolbox", 0, sp_pencil_toolbox_prep, "PencilToolbar",
165 SP_VERB_CONTEXT_PENCIL_PREFS, "tools.freehand.pencil", _("Style of new paths created by Pencil")},
166 { "SPPenContext", "pen_toolbox", 0, sp_pen_toolbox_prep, "PenToolbar",
167 SP_VERB_CONTEXT_PEN_PREFS, "tools.freehand.pen", _("Style of new paths created by Pen")},
168 { "SPDynaDrawContext", "calligraphy_toolbox", 0, sp_calligraphy_toolbox_prep,"CalligraphyToolbar",
169 SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "tools.calligraphic", _("Style of new calligraphic strokes")},
170 { "SPTextContext", "text_toolbox", sp_text_toolbox_new, 0, 0,
171 SP_VERB_INVALID, 0, 0},
172 { "SPDropperContext", "dropper_toolbox", 0, sp_dropper_toolbox_prep, "DropperToolbar",
173 SP_VERB_INVALID, 0, 0},
174 { "SPGradientContext", "gradient_toolbox", sp_gradient_toolbox_new, 0, 0,
175 SP_VERB_INVALID, 0, 0},
176 { "SPConnectorContext", "connector_toolbox", 0, sp_connector_toolbox_prep, "ConnectorToolbar",
177 SP_VERB_INVALID, 0, 0},
178 { "SPFloodContext", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
179 SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "tools.paintbucket", _("Style of Paint Bucket fill objects")},
180 { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
181 };
184 static gchar const * ui_descr =
185 "<ui>"
186 " <toolbar name='SelectToolbar'>"
187 " <toolitem action='ObjectRotate90CCW' />"
188 " <toolitem action='ObjectRotate90' />"
189 " <toolitem action='ObjectFlipHorizontally' />"
190 " <toolitem action='ObjectFlipVertically' />"
191 " <separator />"
192 " <toolitem action='SelectionToBack' />"
193 " <toolitem action='SelectionLower' />"
194 " <toolitem action='SelectionRaise' />"
195 " <toolitem action='SelectionToFront' />"
196 " <separator />"
197 " <toolitem action='XAction' />"
198 " <toolitem action='YAction' />"
199 " <toolitem action='WidthAction' />"
200 " <toolitem action='LockAction' />"
201 " <toolitem action='HeightAction' />"
202 " <toolitem action='UnitsAction' />"
203 " <separator />"
204 " <toolitem action='transform_stroke' />"
205 " <toolitem action='transform_corners' />"
206 " <toolitem action='transform_gradient' />"
207 " <toolitem action='transform_pattern' />"
208 " </toolbar>"
210 " <toolbar name='NodeToolbar'>"
211 " <toolitem action='NodeInsertAction' />"
212 " <toolitem action='NodeDeleteAction' />"
213 " <separator />"
214 " <toolitem action='NodeJoinAction' />"
215 " <toolitem action='NodeJoinSegmentAction' />"
216 " <toolitem action='NodeDeleteSegmentAction' />"
217 " <toolitem action='NodeBreakAction' />"
218 " <separator />"
219 " <toolitem action='NodeCuspAction' />"
220 " <toolitem action='NodeSmoothAction' />"
221 " <toolitem action='NodeSymmetricAction' />"
222 " <separator />"
223 " <toolitem action='NodeLineAction' />"
224 " <toolitem action='NodeCurveAction' />"
225 " <separator />"
226 " <toolitem action='ObjectToPath' />"
227 " <toolitem action='StrokeToPath' />"
228 " <separator />"
229 " <toolitem action='NodesShowHandlesAction' />"
230 " </toolbar>"
232 " <toolbar name='ZoomToolbar'>"
233 " <toolitem action='ZoomIn' />"
234 " <toolitem action='ZoomOut' />"
235 " <separator />"
236 " <toolitem action='ZoomSelection' />"
237 " <toolitem action='ZoomDrawing' />"
238 " <toolitem action='ZoomPage' />"
239 " <toolitem action='ZoomPageWidth' />"
240 " <separator />"
241 " <toolitem action='ZoomPrev' />"
242 " <toolitem action='ZoomNext' />"
243 " <separator />"
244 " <toolitem action='Zoom1:0' />"
245 " <toolitem action='Zoom1:2' />"
246 " <toolitem action='Zoom2:1' />"
247 " </toolbar>"
249 " <toolbar name='StarToolbar'>"
250 " <separator />"
251 " <toolitem action='StarStateAction' />"
252 " <separator />"
253 " <toolitem action='FlatAction' />"
254 " <separator />"
255 " <toolitem action='MagnitudeAction' />"
256 " <toolitem action='SpokeAction' />"
257 " <toolitem action='RoundednessAction' />"
258 " <toolitem action='RandomizationAction' />"
259 " <separator />"
260 " <toolitem action='StarResetAction' />"
261 " </toolbar>"
263 " <toolbar name='RectToolbar'>"
264 " <toolitem action='RectStateAction' />"
265 " <toolitem action='RectWidthAction' />"
266 " <toolitem action='RectHeightAction' />"
267 " <toolitem action='RadiusXAction' />"
268 " <toolitem action='RadiusYAction' />"
269 " <toolitem action='RectUnitsAction' />"
270 " <separator />"
271 " <toolitem action='RectResetAction' />"
272 " </toolbar>"
274 " <toolbar name='SpiralToolbar'>"
275 " <toolitem action='SpiralStateAction' />"
276 " <toolitem action='SpiralRevolutionAction' />"
277 " <toolitem action='SpiralExpansionAction' />"
278 " <toolitem action='SpiralT0Action' />"
279 " <separator />"
280 " <toolitem action='SpiralResetAction' />"
281 " </toolbar>"
283 " <toolbar name='PenToolbar'>"
284 " </toolbar>"
286 " <toolbar name='PencilToolbar'>"
287 " </toolbar>"
289 " <toolbar name='CalligraphyToolbar'>"
290 " <separator />"
291 " <toolitem action='CalligraphyWidthAction' />"
292 " <toolitem action='ThinningAction' />"
293 " <separator />"
294 " <toolitem action='AngleAction' />"
295 " <toolitem action='FixationAction' />"
296 " <toolitem action='CapRoundingAction' />"
297 " <separator />"
298 " <toolitem action='TremorAction' />"
299 " <toolitem action='WiggleAction' />"
300 " <toolitem action='MassAction' />"
301 " <separator />"
302 " <toolitem action='TraceAction' />"
303 " <toolitem action='PressureAction' />"
304 " <toolitem action='TiltAction' />"
305 " <toolitem action='CalligraphyResetAction' />"
306 " </toolbar>"
308 " <toolbar name='ArcToolbar'>"
309 " <toolitem action='ArcStateAction' />"
310 " <separator />"
311 " <toolitem action='ArcStartAction' />"
312 " <toolitem action='ArcEndAction' />"
313 " <separator />"
314 " <toolitem action='ArcOpenAction' />"
315 " <separator />"
316 " <toolitem action='ArcResetAction' />"
317 " <separator />"
318 " </toolbar>"
320 " <toolbar name='PaintbucketToolbar'>"
321 " <toolitem action='ChannelsAction' />"
322 " <separator />"
323 " <toolitem action='ThresholdAction' />"
324 " <separator />"
325 " <toolitem action='OffsetAction' />"
326 " <toolitem action='PaintbucketUnitsAction' />"
327 " <separator />"
328 " <toolitem action='PaintbucketResetAction' />"
329 " </toolbar>"
331 " <toolbar name='DropperToolbar'>"
332 " <toolitem action='DropperPickAlphaAction' />"
333 " <toolitem action='DropperSetAlphaAction' />"
334 " </toolbar>"
336 " <toolbar name='ConnectorToolbar'>"
337 " <toolitem action='ConnectorAvoidAction' />"
338 " <toolitem action='ConnectorIgnoreAction' />"
339 " <toolitem action='ConnectorSpacingAction' />"
340 " <toolitem action='ConnectorGraphAction' />"
341 " <toolitem action='ConnectorLengthAction' />"
342 " <toolitem action='ConnectorDirectedAction' />"
343 " <toolitem action='ConnectorOverlapAction' />"
344 " </toolbar>"
346 "</ui>"
347 ;
349 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
351 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
353 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
354 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
356 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
357 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
359 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
360 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
362 /* Global text entry widgets necessary for update */
363 /* GtkWidget *dropper_rgb_entry,
364 *dropper_opacity_entry ; */
365 // should be made a private member once this is converted to class
367 static void delete_connection(GObject *obj, sigc::connection *connection) {
368 connection->disconnect();
369 delete connection;
370 }
372 static void purge_repr_listener( GObject* obj, GObject* tbl )
373 {
374 (void)obj;
375 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
376 if (oldrepr) { // remove old listener
377 sp_repr_remove_listener_by_data(oldrepr, tbl);
378 Inkscape::GC::release(oldrepr);
379 oldrepr = 0;
380 g_object_set_data( tbl, "repr", NULL );
381 }
382 }
384 GtkWidget *
385 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
386 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
387 Inkscape::UI::View::View *view, GtkTooltips *tt)
388 {
389 SPAction *action = verb->get_action(view);
390 if (!action) return NULL;
392 SPAction *doubleclick_action;
393 if (doubleclick_verb)
394 doubleclick_action = doubleclick_verb->get_action(view);
395 else
396 doubleclick_action = NULL;
398 /* fixme: Handle sensitive/unsensitive */
399 /* fixme: Implement sp_button_new_from_action */
400 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
401 gtk_widget_show(b);
402 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
404 return b;
405 }
407 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
408 Inkscape::UI::View::View *view, GtkTooltips *tt)
409 {
410 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
411 }
413 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
414 Inkscape::UI::View::View *view, GtkTooltips *tt)
415 {
416 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
417 }
420 static void trigger_sp_action( GtkAction* act, gpointer user_data )
421 {
422 SPAction* targetAction = SP_ACTION(user_data);
423 if ( targetAction ) {
424 sp_action_perform( targetAction, NULL );
425 }
426 }
428 static void sp_action_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data)
429 {
430 if ( data ) {
431 GtkAction* act = GTK_ACTION(data);
432 gtk_action_set_sensitive( act, sensitive );
433 }
434 }
436 static SPActionEventVector action_event_vector = {
437 {NULL},
438 NULL,
439 NULL,
440 sp_action_action_set_sensitive,
441 NULL,
442 NULL
443 };
445 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
446 {
447 GtkAction* act = 0;
449 SPAction* targetAction = verb->get_action(view);
450 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
451 act = GTK_ACTION(inky);
452 gtk_action_set_sensitive( act, targetAction->sensitive );
454 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
456 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
457 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
459 return act;
460 }
462 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
463 {
464 Inkscape::UI::View::View *view = desktop;
465 gint verbsToUse[] = {
466 // disabled until we have icons for them:
467 //find
468 //SP_VERB_EDIT_TILE,
469 //SP_VERB_EDIT_UNTILE,
470 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
471 SP_VERB_DIALOG_DISPLAY,
472 SP_VERB_DIALOG_FILL_STROKE,
473 SP_VERB_DIALOG_NAMEDVIEW,
474 SP_VERB_DIALOG_TEXT,
475 SP_VERB_DIALOG_XML_EDITOR,
476 SP_VERB_EDIT_CLONE,
477 SP_VERB_EDIT_COPY,
478 SP_VERB_EDIT_CUT,
479 SP_VERB_EDIT_DUPLICATE,
480 SP_VERB_EDIT_PASTE,
481 SP_VERB_EDIT_REDO,
482 SP_VERB_EDIT_UNDO,
483 SP_VERB_EDIT_UNLINK_CLONE,
484 SP_VERB_FILE_EXPORT,
485 SP_VERB_FILE_IMPORT,
486 SP_VERB_FILE_NEW,
487 SP_VERB_FILE_OPEN,
488 SP_VERB_FILE_PRINT,
489 SP_VERB_FILE_SAVE,
490 SP_VERB_OBJECT_TO_CURVE,
491 SP_VERB_SELECTION_GROUP,
492 SP_VERB_SELECTION_OUTLINE,
493 SP_VERB_SELECTION_UNGROUP,
494 SP_VERB_ZOOM_1_1,
495 SP_VERB_ZOOM_1_2,
496 SP_VERB_ZOOM_2_1,
497 SP_VERB_ZOOM_DRAWING,
498 SP_VERB_ZOOM_IN,
499 SP_VERB_ZOOM_NEXT,
500 SP_VERB_ZOOM_OUT,
501 SP_VERB_ZOOM_PAGE,
502 SP_VERB_ZOOM_PAGE_WIDTH,
503 SP_VERB_ZOOM_PREV,
504 SP_VERB_ZOOM_SELECTION,
505 };
507 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
508 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
510 static std::map<SPDesktop*, GtkActionGroup*> groups;
511 GtkActionGroup* mainActions = 0;
512 if ( groups.find(desktop) != groups.end() ) {
513 mainActions = groups[desktop];
514 }
516 if ( !mainActions ) {
517 mainActions = gtk_action_group_new("main");
518 groups[desktop] = mainActions;
519 }
521 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
522 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
523 if ( verb ) {
524 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
525 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
526 gtk_action_group_add_action( mainActions, act );
527 }
528 }
529 }
531 return mainActions;
532 }
535 GtkWidget *
536 sp_tool_toolbox_new()
537 {
538 GtkTooltips *tt = gtk_tooltips_new();
539 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
541 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
542 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
544 gtk_widget_set_sensitive(tb, FALSE);
546 GtkWidget *hb = gtk_handle_box_new();
547 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
548 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
549 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
551 gtk_container_add(GTK_CONTAINER(hb), tb);
552 gtk_widget_show(GTK_WIDGET(tb));
554 sigc::connection* conn = new sigc::connection;
555 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
557 return hb;
558 }
560 static void
561 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
562 {
563 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
564 gtk_widget_queue_resize(child);
565 }
567 static void
568 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
569 {
570 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
571 gtk_widget_queue_resize(child);
572 }
574 GtkWidget *
575 sp_aux_toolbox_new()
576 {
577 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
579 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
580 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
581 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
582 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
583 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
585 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
586 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
588 gtk_widget_set_sensitive(tb, FALSE);
590 GtkWidget *hb = gtk_handle_box_new();
591 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
592 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
593 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
595 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
596 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
598 gtk_container_add(GTK_CONTAINER(hb), tb);
599 gtk_widget_show(GTK_WIDGET(tb));
601 sigc::connection* conn = new sigc::connection;
602 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
604 return hb;
605 }
607 //####################################
608 //# Commands Bar
609 //####################################
611 GtkWidget *
612 sp_commands_toolbox_new()
613 {
614 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
616 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
617 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
618 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
619 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
620 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
622 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
623 gtk_widget_set_sensitive(tb, FALSE);
625 GtkWidget *hb = gtk_handle_box_new();
626 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
627 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
628 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
630 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
631 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
633 gtk_container_add(GTK_CONTAINER(hb), tb);
634 gtk_widget_show(GTK_WIDGET(tb));
636 sigc::connection* conn = new sigc::connection;
637 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
639 return hb;
640 }
643 //####################################
644 //# node editing callbacks
645 //####################################
647 void
648 sp_node_path_edit_add(void)
649 {
650 sp_node_selected_add_node();
651 }
653 void
654 sp_node_path_edit_delete(void)
655 {
656 sp_node_selected_delete();
657 }
659 void
660 sp_node_path_edit_delete_segment(void)
661 {
662 sp_node_selected_delete_segment();
663 }
665 void
666 sp_node_path_edit_break(void)
667 {
668 sp_node_selected_break();
669 }
671 void
672 sp_node_path_edit_join(void)
673 {
674 sp_node_selected_join();
675 }
677 void
678 sp_node_path_edit_join_segment(void)
679 {
680 sp_node_selected_join_segment();
681 }
683 void
684 sp_node_path_edit_toline(void)
685 {
686 sp_node_selected_set_line_type(NR_LINETO);
687 }
689 void
690 sp_node_path_edit_tocurve(void)
691 {
692 sp_node_selected_set_line_type(NR_CURVETO);
693 }
695 void
696 sp_node_path_edit_cusp(void)
697 {
698 sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
699 }
701 void
702 sp_node_path_edit_smooth(void)
703 {
704 sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
705 }
707 void
708 sp_node_path_edit_symmetrical(void)
709 {
710 sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
711 }
713 static void toggle_show_handles (GtkToggleAction *act, gpointer data) {
714 bool show = gtk_toggle_action_get_active( act );
715 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
716 sp_nodepath_show_handles(show);
717 }
719 //################################
720 //## Node Editing Toolbox ##
721 //################################
723 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
724 {
725 {
726 InkAction* inky = ink_action_new( "NodeInsertAction",
727 _("Insert"),
728 _("Insert new nodes into selected segments"),
729 "node_insert",
730 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
731 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
732 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
733 }
735 {
736 InkAction* inky = ink_action_new( "NodeDeleteAction",
737 _("Delete"),
738 _("Delete selected nodes"),
739 "node_delete",
740 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
741 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
742 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
743 }
745 {
746 InkAction* inky = ink_action_new( "NodeJoinAction",
747 _("Join"),
748 _("Join selected endnodes"),
749 "node_join",
750 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
751 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
752 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
753 }
755 {
756 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
757 _("Join Segment"),
758 _("Join selected endnodes with a new segment"),
759 "node_join_segment",
760 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
761 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
762 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
763 }
765 {
766 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
767 _("Delete Segment"),
768 _("Split path between two non-endpoint nodes"),
769 "node_delete_segment",
770 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
771 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
772 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
773 }
775 {
776 InkAction* inky = ink_action_new( "NodeBreakAction",
777 _("Node Break"),
778 _("Break path at selected nodes"),
779 "node_break",
780 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
781 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
782 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
783 }
785 {
786 InkAction* inky = ink_action_new( "NodeCuspAction",
787 _("Node Cusp"),
788 _("Make selected nodes corner"),
789 "node_cusp",
790 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
791 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
792 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
793 }
795 {
796 InkAction* inky = ink_action_new( "NodeSmoothAction",
797 _("Node Smooth"),
798 _("Make selected nodes smooth"),
799 "node_smooth",
800 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
801 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
802 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
803 }
805 {
806 InkAction* inky = ink_action_new( "NodeSymmetricAction",
807 _("Node Symmetric"),
808 _("Make selected nodes symmetric"),
809 "node_symmetric",
810 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
811 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
812 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
813 }
815 {
816 InkAction* inky = ink_action_new( "NodeLineAction",
817 _("Node Line"),
818 _("Make selected segments lines"),
819 "node_line",
820 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
821 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
822 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
823 }
825 {
826 InkAction* inky = ink_action_new( "NodeCurveAction",
827 _("Node Curve"),
828 _("Make selected segments curves"),
829 "node_curve",
830 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
831 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
832 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
833 }
835 {
836 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
837 _("Show Handles"),
838 _("Show the Bezier handles of selected nodes"),
839 "nodes_show_handles",
840 Inkscape::ICON_SIZE_DECORATION );
841 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
842 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
843 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
844 }
846 } // end of sp_node_toolbox_prep()
849 //########################
850 //## Zoom Toolbox ##
851 //########################
853 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
854 {
855 // no custom GtkAction setup needed
856 } // end of sp_zoom_toolbox_prep()
858 void
859 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
860 {
861 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")));
862 }
865 void
866 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
867 {
868 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")));
869 }
871 void
872 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
873 {
874 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")));
875 }
877 static void
878 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
879 {
880 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
881 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
883 if (old_desktop) {
884 GList *children, *iter;
886 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
887 for ( iter = children ; iter ; iter = iter->next ) {
888 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
889 }
890 g_list_free(children);
891 }
893 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
895 if (desktop) {
896 gtk_widget_set_sensitive(toolbox, TRUE);
897 setup_func(toolbox, desktop);
898 update_func(desktop, desktop->event_context, toolbox);
899 *conn = desktop->connectEventContextChanged
900 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
901 } else {
902 gtk_widget_set_sensitive(toolbox, FALSE);
903 }
905 } // end of toolbox_set_desktop()
908 static void
909 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
910 {
911 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
912 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.tools", "small", 0, 0, 1 );
913 if ( (shrinkLeft == 0) && (prefs_get_int_attribute_limited( "toolbox.tools", "small", 1, 0, 1 ) == 1) ) {
914 // "toolbox.tools" was not set. Fallback to older value
915 shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
917 // Copy the setting forwards
918 prefs_set_int_attribute( "toolbox.tools", "small", shrinkLeft );
919 }
920 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
922 for (int i = 0 ; tools[i].type_name ; i++ ) {
923 GtkWidget *button =
924 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
925 SP_BUTTON_TYPE_TOGGLE,
926 Inkscape::Verb::get(tools[i].verb),
927 Inkscape::Verb::get(tools[i].doubleclick_verb),
928 desktop,
929 tooltips );
931 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
932 (gpointer)button );
933 }
934 }
937 static void
938 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
939 {
940 gchar const *const tname = ( eventcontext
941 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
942 : NULL );
943 for (int i = 0 ; tools[i].type_name ; i++ ) {
944 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
945 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
946 }
947 }
949 static void
950 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
951 {
952 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
953 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
954 GtkUIManager* mgr = gtk_ui_manager_new();
955 GError* errVal = 0;
956 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
957 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
959 std::map<std::string, GtkWidget*> dataHolders;
961 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
962 if ( aux_toolboxes[i].prep_func ) {
963 // converted to GtkActions and UIManager
965 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
966 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
967 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
968 dataHolders[aux_toolboxes[i].type_name] = kludge;
969 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
970 } else {
972 GtkWidget *sub_toolbox = 0;
973 if (aux_toolboxes[i].create_func == NULL)
974 sub_toolbox = sp_empty_toolbox_new(desktop);
975 else {
976 sub_toolbox = aux_toolboxes[i].create_func(desktop);
977 }
979 gtk_size_group_add_widget( grouper, sub_toolbox );
981 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
982 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
984 }
985 }
987 // Second pass to create toolbars *after* all GtkActions are created
988 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
989 if ( aux_toolboxes[i].prep_func ) {
990 // converted to GtkActions and UIManager
992 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
994 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
995 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
997 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
998 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
999 g_free( tmp );
1000 tmp = 0;
1002 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1003 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1004 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1005 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1006 }
1007 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1010 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1012 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1013 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1014 swatch->setDesktop( desktop );
1015 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1016 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1017 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1018 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 );
1019 }
1021 gtk_widget_show_all( holder );
1022 sp_set_font_size_smaller( holder );
1024 gtk_size_group_add_widget( grouper, holder );
1026 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1027 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1028 }
1029 }
1031 g_object_unref( G_OBJECT(grouper) );
1032 }
1034 static void
1035 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1036 {
1037 gchar const *tname = ( eventcontext
1038 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1039 : NULL );
1040 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1041 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1042 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1043 gtk_widget_show_all(sub_toolbox);
1044 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1045 } else {
1046 gtk_widget_hide(sub_toolbox);
1047 }
1048 }
1049 }
1051 static void
1052 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1053 {
1054 gchar const * descr =
1055 "<ui>"
1056 " <toolbar name='CommandsToolbar'>"
1057 " <toolitem action='FileNew' />"
1058 " <toolitem action='FileOpen' />"
1059 " <toolitem action='FileSave' />"
1060 " <toolitem action='FilePrint' />"
1061 " <separator />"
1062 " <toolitem action='FileImport' />"
1063 " <toolitem action='FileExport' />"
1064 " <separator />"
1065 " <toolitem action='EditUndo' />"
1066 " <toolitem action='EditRedo' />"
1067 " <separator />"
1068 " <toolitem action='EditCopy' />"
1069 " <toolitem action='EditCut' />"
1070 " <toolitem action='EditPaste' />"
1071 " <separator />"
1072 " <toolitem action='ZoomSelection' />"
1073 " <toolitem action='ZoomDrawing' />"
1074 " <toolitem action='ZoomPage' />"
1075 " <separator />"
1076 " <toolitem action='EditDuplicate' />"
1077 " <toolitem action='EditClone' />"
1078 " <toolitem action='EditUnlinkClone' />"
1079 " <separator />"
1080 " <toolitem action='SelectionGroup' />"
1081 " <toolitem action='SelectionUnGroup' />"
1082 " <separator />"
1083 " <toolitem action='DialogFillStroke' />"
1084 " <toolitem action='DialogText' />"
1085 " <toolitem action='DialogXMLEditor' />"
1086 " <toolitem action='DialogAlignDistribute' />"
1087 " <separator />"
1088 " <toolitem action='DialogPreferences' />"
1089 " <toolitem action='DialogDocumentProperties' />"
1090 " </toolbar>"
1091 "</ui>";
1092 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1095 GtkUIManager* mgr = gtk_ui_manager_new();
1096 GError* errVal = 0;
1098 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1099 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1101 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1102 if ( prefs_get_int_attribute_limited( "toolbox", "icononly", 1, 0, 1 ) ) {
1103 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1104 }
1105 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1106 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1107 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1110 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1111 }
1113 static void
1114 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1115 {
1116 }
1118 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1119 {
1120 gtk_widget_show(toolbox_toplevel);
1121 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1123 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1124 if (!shown_toolbox) {
1125 return;
1126 }
1127 gtk_widget_show(toolbox);
1129 // need to show the spacer, or the padding will be off
1130 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1131 gtk_widget_show(spacer);
1133 gtk_widget_show_all(shown_toolbox);
1134 }
1136 void
1137 aux_toolbox_space(GtkWidget *tb, gint space)
1138 {
1139 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1140 }
1142 static GtkWidget *
1143 sp_empty_toolbox_new(SPDesktop *desktop)
1144 {
1145 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1146 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1147 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1149 gtk_widget_show_all(tbl);
1150 sp_set_font_size_smaller (tbl);
1152 return tbl;
1153 }
1155 // helper UI functions
1157 GtkWidget *
1158 sp_tb_spinbutton(
1159 gchar *label, gchar const *tooltip,
1160 gchar const *path, gchar const *data, gdouble def,
1161 GtkWidget *us,
1162 GtkWidget *tbl,
1163 gboolean altx, gchar const *altx_mark,
1164 gdouble lower, gdouble upper, gdouble step, gdouble page,
1165 void (*callback)(GtkAdjustment *, GtkWidget *),
1166 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1167 {
1168 GtkTooltips *tt = gtk_tooltips_new();
1170 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1172 GtkWidget *l = gtk_label_new(label);
1173 gtk_widget_show(l);
1174 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1175 gtk_container_add(GTK_CONTAINER(hb), l);
1177 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1178 lower, upper, step, page, page);
1179 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1180 if (us)
1181 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1183 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1184 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1185 if (altx)
1186 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1187 gtk_widget_set_size_request(sb,
1188 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1189 AUX_SPINBUTTON_HEIGHT);
1190 gtk_widget_show(sb);
1191 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1192 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1193 gtk_container_add(GTK_CONTAINER(hb), sb);
1194 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1196 return hb;
1197 }
1199 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
1200 gchar const *label, gchar const *tooltip,
1201 gchar const *path, gchar const *data, gdouble def,
1202 GtkWidget *focusTarget,
1203 GtkWidget *us,
1204 GObject *dataKludge,
1205 gboolean altx, gchar const *altx_mark,
1206 gdouble lower, gdouble upper, gdouble step, gdouble page,
1207 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
1208 void (*callback)(GtkAdjustment *, GObject *),
1209 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
1210 {
1211 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
1212 lower, upper, step, page, page ) );
1213 if (us) {
1214 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
1215 }
1217 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
1219 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
1221 if ( (descrCount > 0) && descrLabels && descrValues ) {
1222 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
1223 }
1225 if ( focusTarget ) {
1226 ege_adjustment_action_set_focuswidget( act, focusTarget );
1227 }
1229 if ( altx && altx_mark ) {
1230 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
1231 }
1233 if ( dataKludge ) {
1234 g_object_set_data( dataKludge, data, adj );
1235 }
1237 // Using a cast just to make sure we pass in the right kind of function pointer
1238 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
1240 return act;
1241 }
1244 #define MODE_LABEL_WIDTH 70
1246 //########################
1247 //## Star ##
1248 //########################
1250 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1251 {
1252 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1254 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1255 // do not remember prefs if this call is initiated by an undo change, because undoing object
1256 // creation sets bogus values to its attributes before it is deleted
1257 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1258 }
1260 // quit if run by the attr_changed listener
1261 if (g_object_get_data( dataKludge, "freeze" )) {
1262 return;
1263 }
1265 // in turn, prevent listener from responding
1266 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1268 bool modmade = false;
1270 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1271 GSList const *items = selection->itemList();
1272 for (; items != NULL; items = items->next) {
1273 if (SP_IS_STAR((SPItem *) items->data)) {
1274 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1275 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1276 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1277 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1278 + M_PI / (gint)adj->value));
1279 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1280 modmade = true;
1281 }
1282 }
1283 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1284 _("Star: Change number of corners"));
1286 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1287 }
1289 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1290 {
1291 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1293 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1294 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1295 }
1297 // quit if run by the attr_changed listener
1298 if (g_object_get_data( dataKludge, "freeze" )) {
1299 return;
1300 }
1302 // in turn, prevent listener from responding
1303 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1305 bool modmade = false;
1306 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1307 GSList const *items = selection->itemList();
1308 for (; items != NULL; items = items->next) {
1309 if (SP_IS_STAR((SPItem *) items->data)) {
1310 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1312 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1313 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1314 if (r2 < r1) {
1315 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1316 } else {
1317 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1318 }
1320 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1321 modmade = true;
1322 }
1323 }
1325 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1326 _("Star: Change spoke ratio"));
1328 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1329 }
1331 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1332 {
1333 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1334 bool flat = ege_select_one_action_get_active( act ) == 0;
1336 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1337 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1338 flat ? "true" : "false" );
1339 }
1341 // quit if run by the attr_changed listener
1342 if (g_object_get_data( dataKludge, "freeze" )) {
1343 return;
1344 }
1346 // in turn, prevent listener from responding
1347 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1349 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1350 GSList const *items = selection->itemList();
1351 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1352 bool modmade = false;
1354 if ( prop_action ) {
1355 gtk_action_set_sensitive( prop_action, !flat );
1356 }
1358 for (; items != NULL; items = items->next) {
1359 if (SP_IS_STAR((SPItem *) items->data)) {
1360 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1361 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1362 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1363 modmade = true;
1364 }
1365 }
1367 if (modmade) {
1368 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1369 flat ? _("Make polygon") : _("Make star"));
1370 }
1372 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1373 }
1375 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1376 {
1377 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1379 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1380 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1381 }
1383 // quit if run by the attr_changed listener
1384 if (g_object_get_data( dataKludge, "freeze" )) {
1385 return;
1386 }
1388 // in turn, prevent listener from responding
1389 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1391 bool modmade = false;
1393 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1394 GSList const *items = selection->itemList();
1395 for (; items != NULL; items = items->next) {
1396 if (SP_IS_STAR((SPItem *) items->data)) {
1397 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1398 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1399 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1400 modmade = true;
1401 }
1402 }
1403 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1404 _("Star: Change rounding"));
1406 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1407 }
1409 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1410 {
1411 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1413 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1414 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1415 }
1417 // quit if run by the attr_changed listener
1418 if (g_object_get_data( dataKludge, "freeze" )) {
1419 return;
1420 }
1422 // in turn, prevent listener from responding
1423 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1425 bool modmade = false;
1427 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1428 GSList const *items = selection->itemList();
1429 for (; items != NULL; items = items->next) {
1430 if (SP_IS_STAR((SPItem *) items->data)) {
1431 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1432 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1433 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1434 modmade = true;
1435 }
1436 }
1437 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1438 _("Star: Change randomization"));
1440 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1441 }
1444 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1445 gchar const *old_value, gchar const *new_value,
1446 bool is_interactive, gpointer data)
1447 {
1448 GtkWidget *tbl = GTK_WIDGET(data);
1450 // quit if run by the _changed callbacks
1451 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1452 return;
1453 }
1455 // in turn, prevent callbacks from responding
1456 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1458 GtkAdjustment *adj = 0;
1460 if (!strcmp(name, "inkscape:randomized")) {
1461 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1462 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1463 } else if (!strcmp(name, "inkscape:rounded")) {
1464 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1465 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1466 } else if (!strcmp(name, "inkscape:flatsided")) {
1467 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1468 char const *flatsides = repr->attribute("inkscape:flatsided");
1469 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1470 if ( flatsides && !strcmp(flatsides,"false") ) {
1471 ege_select_one_action_set_active( flat_action, 1 );
1472 gtk_action_set_sensitive( prop_action, TRUE );
1473 } else {
1474 ege_select_one_action_set_active( flat_action, 0 );
1475 gtk_action_set_sensitive( prop_action, FALSE );
1476 }
1477 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1478 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1479 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1480 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1481 if (r2 < r1) {
1482 gtk_adjustment_set_value(adj, r2/r1);
1483 } else {
1484 gtk_adjustment_set_value(adj, r1/r2);
1485 }
1486 } else if (!strcmp(name, "sodipodi:sides")) {
1487 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1488 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1489 }
1491 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1492 }
1495 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1496 {
1497 NULL, /* child_added */
1498 NULL, /* child_removed */
1499 star_tb_event_attr_changed,
1500 NULL, /* content_changed */
1501 NULL /* order_changed */
1502 };
1505 /**
1506 * \param selection Should not be NULL.
1507 */
1508 static void
1509 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1510 {
1511 int n_selected = 0;
1512 Inkscape::XML::Node *repr = NULL;
1514 purge_repr_listener( tbl, tbl );
1516 for (GSList const *items = selection->itemList();
1517 items != NULL;
1518 items = items->next)
1519 {
1520 if (SP_IS_STAR((SPItem *) items->data)) {
1521 n_selected++;
1522 repr = SP_OBJECT_REPR((SPItem *) items->data);
1523 }
1524 }
1526 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1528 if (n_selected == 0) {
1529 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1530 } else if (n_selected == 1) {
1531 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1533 if (repr) {
1534 g_object_set_data( tbl, "repr", repr );
1535 Inkscape::GC::anchor(repr);
1536 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1537 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1538 }
1539 } else {
1540 // FIXME: implement averaging of all parameters for multiple selected stars
1541 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1542 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1543 }
1544 }
1547 static void sp_stb_defaults( GtkWidget *widget, GObject *dataKludge )
1548 {
1549 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1550 // callbacks to lump all the changes for all selected objects in one undo step
1552 GtkAdjustment *adj = 0;
1554 // fixme: make settable in prefs!
1555 gint mag = 5;
1556 gdouble prop = 0.5;
1557 gboolean flat = FALSE;
1558 gdouble randomized = 0;
1559 gdouble rounded = 0;
1561 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1562 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1564 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1565 gtk_action_set_sensitive( sb2, !flat );
1567 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1568 gtk_adjustment_set_value(adj, mag);
1569 gtk_adjustment_value_changed(adj);
1571 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1572 gtk_adjustment_set_value(adj, prop);
1573 gtk_adjustment_value_changed(adj);
1575 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1576 gtk_adjustment_set_value(adj, rounded);
1577 gtk_adjustment_value_changed(adj);
1579 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1580 gtk_adjustment_set_value(adj, randomized);
1581 gtk_adjustment_value_changed(adj);
1582 }
1585 void
1586 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1587 {
1588 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1589 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1590 GtkWidget *l = gtk_label_new(NULL);
1591 gtk_label_set_markup(GTK_LABEL(l), title);
1592 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1593 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1594 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1595 }
1598 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1599 {
1600 {
1601 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1602 ege_output_action_set_use_markup( act, TRUE );
1603 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1604 g_object_set_data( holder, "mode_action", act );
1605 }
1607 {
1608 //EgeAdjustmentAction* calligraphy_angle = 0;
1609 EgeAdjustmentAction* eact = 0;
1610 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1611 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1613 /* Flatsided checkbox */
1614 {
1615 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1617 GtkTreeIter iter;
1618 gtk_list_store_append( model, &iter );
1619 gtk_list_store_set( model, &iter,
1620 0, _("Polygon"),
1621 1, _("Regular polygon (with one handle) instead of a star"),
1622 2, "star_flat",
1623 -1 );
1625 gtk_list_store_append( model, &iter );
1626 gtk_list_store_set( model, &iter,
1627 0, _("Star"),
1628 1, _("Star instead of a regular polygon (with one handle)"),
1629 2, "star_angled",
1630 -1 );
1632 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
1633 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1634 g_object_set_data( holder, "flat_action", act );
1636 ege_select_one_action_set_appearance( act, "full" );
1637 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1638 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1639 ege_select_one_action_set_icon_column( act, 2 );
1640 ege_select_one_action_set_tooltip_column( act, 1 );
1642 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1643 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1644 }
1646 /* Magnitude */
1647 //gchar const* labels[] = {_("tri (default)"), _("quad"), _("pent")};
1648 //gdouble values[] = {3, 4, 5};
1649 eact = create_adjustment_action( "MagnitudeAction",
1650 _("Corners:"), _("Number of corners of a polygon or star"),
1651 "tools.shapes.star", "magnitude", 3,
1652 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1653 3, 1024, 1, 5,
1654 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
1655 sp_stb_magnitude_value_changed,
1656 1.0, 0 );
1657 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1658 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1660 /* Spoke ratio */
1661 //gchar const* labels2[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1662 //gdouble values2[] = {-90, 0, 30, 90};
1663 eact = create_adjustment_action( "SpokeAction",
1664 _("Spoke ratio:"),
1665 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1666 // Base radius is the same for the closest handle.
1667 _("Base radius to tip radius ratio"),
1668 "tools.shapes.star", "proportion", 0.5,
1669 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1670 0.01, 1.0, 0.01, 0.1,
1671 0, 0, 0, // labels2, values2, G_N_ELEMENTS(labels2),
1672 sp_stb_proportion_value_changed );
1673 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1674 g_object_set_data( holder, "prop_action", eact );
1676 if ( !isFlatSided ) {
1677 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1678 } else {
1679 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1680 }
1682 /* Roundedness */
1683 //gchar const* labels3[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1684 //gdouble values3[] = {-90, 0, 30, 90};
1685 eact = create_adjustment_action( "RoundednessAction",
1686 _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1687 "tools.shapes.star", "rounded", 0.0,
1688 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1689 -100.0, 100.0, 0.01, 0.1,
1690 0, 0, 0, // labels3, values3, G_N_ELEMENTS(labels3),
1691 sp_stb_rounded_value_changed );
1692 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1693 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1695 /* Randomization */
1696 //gchar const* labels4[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1697 //gdouble values4[] = {-90, 0, 30, 90};
1698 eact = create_adjustment_action( "RandomizationAction",
1699 _("Randomized:"), _("Scatter randomly the corners and angles"),
1700 "tools.shapes.star", "randomized", 0.0,
1701 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1702 -10.0, 10.0, 0.001, 0.01,
1703 0, 0, 0, // labels4, values4, G_N_ELEMENTS(labels4),
1704 sp_stb_randomized_value_changed, 0.1, 3 );
1705 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1706 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1707 }
1709 {
1710 /* Reset */
1711 {
1712 GtkAction* act = gtk_action_new( "StarResetAction",
1713 _("Defaults"),
1714 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1715 GTK_STOCK_CLEAR );
1716 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1717 gtk_action_group_add_action( mainActions, act );
1718 gtk_action_set_sensitive( act, TRUE );
1719 }
1720 }
1722 sigc::connection *connection = new sigc::connection(
1723 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1724 );
1725 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1726 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1727 }
1730 //########################
1731 //## Rect ##
1732 //########################
1734 static void sp_rtb_sensitivize( GObject *tbl )
1735 {
1736 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
1737 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
1738 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
1740 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
1741 gtk_action_set_sensitive( not_rounded, FALSE );
1742 } else {
1743 gtk_action_set_sensitive( not_rounded, TRUE );
1744 }
1745 }
1748 static void
1749 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
1750 void (*setter)(SPRect *, gdouble))
1751 {
1752 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1754 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1755 SPUnit const *unit = tracker->getActiveUnit();
1757 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1758 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1759 }
1761 // quit if run by the attr_changed listener
1762 if (g_object_get_data( tbl, "freeze" )) {
1763 return;
1764 }
1766 // in turn, prevent listener from responding
1767 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1769 bool modmade = false;
1770 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1771 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1772 if (SP_IS_RECT(items->data)) {
1773 if (adj->value != 0) {
1774 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1775 } else {
1776 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1777 }
1778 modmade = true;
1779 }
1780 }
1782 sp_rtb_sensitivize( tbl );
1784 if (modmade) {
1785 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
1786 _("Change rectangle"));
1787 }
1789 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1790 }
1792 static void
1793 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
1794 {
1795 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1796 }
1798 static void
1799 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
1800 {
1801 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1802 }
1804 static void
1805 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
1806 {
1807 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1808 }
1810 static void
1811 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
1812 {
1813 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1814 }
1818 static void
1819 sp_rtb_defaults( GtkWidget *widget, GObject *obj)
1820 {
1821 GtkAdjustment *adj = 0;
1823 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
1824 gtk_adjustment_set_value(adj, 0.0);
1825 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1826 gtk_adjustment_value_changed(adj);
1828 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
1829 gtk_adjustment_set_value(adj, 0.0);
1830 gtk_adjustment_value_changed(adj);
1832 sp_rtb_sensitivize( obj );
1833 }
1835 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1836 gchar const *old_value, gchar const *new_value,
1837 bool is_interactive, gpointer data)
1838 {
1839 GObject *tbl = G_OBJECT(data);
1841 // quit if run by the _changed callbacks
1842 if (g_object_get_data( tbl, "freeze" )) {
1843 return;
1844 }
1846 // in turn, prevent callbacks from responding
1847 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
1849 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1850 SPUnit const *unit = tracker->getActiveUnit();
1852 gpointer item = g_object_get_data( tbl, "item" );
1853 if (item && SP_IS_RECT(item)) {
1854 {
1855 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
1856 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1857 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1858 }
1860 {
1861 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
1862 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1863 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1864 }
1866 {
1867 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
1868 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1869 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1870 }
1872 {
1873 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
1874 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1875 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1876 }
1877 }
1879 sp_rtb_sensitivize( tbl );
1881 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1882 }
1885 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1886 NULL, /* child_added */
1887 NULL, /* child_removed */
1888 rect_tb_event_attr_changed,
1889 NULL, /* content_changed */
1890 NULL /* order_changed */
1891 };
1893 /**
1894 * \param selection should not be NULL.
1895 */
1896 static void
1897 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1898 {
1899 int n_selected = 0;
1900 Inkscape::XML::Node *repr = NULL;
1901 SPItem *item = NULL;
1903 if ( g_object_get_data( tbl, "repr" ) ) {
1904 g_object_set_data( tbl, "item", NULL );
1905 }
1906 purge_repr_listener( tbl, tbl );
1908 for (GSList const *items = selection->itemList();
1909 items != NULL;
1910 items = items->next) {
1911 if (SP_IS_RECT((SPItem *) items->data)) {
1912 n_selected++;
1913 item = (SPItem *) items->data;
1914 repr = SP_OBJECT_REPR(item);
1915 }
1916 }
1918 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1920 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
1922 if (n_selected == 0) {
1923 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1925 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1926 gtk_action_set_sensitive(w, FALSE);
1927 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1928 gtk_action_set_sensitive(h, FALSE);
1930 } else if (n_selected == 1) {
1931 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1932 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
1934 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1935 gtk_action_set_sensitive(w, TRUE);
1936 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1937 gtk_action_set_sensitive(h, TRUE);
1939 if (repr) {
1940 g_object_set_data( tbl, "repr", repr );
1941 g_object_set_data( tbl, "item", item );
1942 Inkscape::GC::anchor(repr);
1943 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1944 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1945 }
1946 } else {
1947 // FIXME: implement averaging of all parameters for multiple selected
1948 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1949 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1950 sp_rtb_sensitivize( tbl );
1951 }
1952 }
1955 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1956 {
1957 EgeAdjustmentAction* eact = 0;
1959 {
1960 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
1961 ege_output_action_set_use_markup( act, TRUE );
1962 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1963 g_object_set_data( holder, "mode_action", act );
1964 }
1966 // rx/ry units menu: create
1967 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1968 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
1969 // fixme: add % meaning per cent of the width/height
1970 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1971 g_object_set_data( holder, "tracker", tracker );
1973 /* W */
1974 {
1975 eact = create_adjustment_action( "RectWidthAction",
1976 _("W:"), _("Width of rectangle"),
1977 "tools.shapes.rect", "width", 0,
1978 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
1979 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1980 0, 0, 0,
1981 sp_rtb_width_value_changed );
1982 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1983 g_object_set_data( holder, "width_action", eact );
1984 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1985 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1986 }
1988 /* H */
1989 {
1990 eact = create_adjustment_action( "RectHeightAction",
1991 _("H:"), _("Height of rectangle"),
1992 "tools.shapes.rect", "height", 0,
1993 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1994 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1995 0, 0, 0,
1996 sp_rtb_height_value_changed );
1997 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1998 g_object_set_data( holder, "height_action", eact );
1999 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
2000 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2001 }
2003 /* rx */
2004 {
2005 eact = create_adjustment_action( "RadiusXAction",
2006 _("Rx:"), _("Horizontal radius of rounded corners"),
2007 "tools.shapes.rect", "rx", 0,
2008 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2009 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2010 0, 0, 0,
2011 sp_rtb_rx_value_changed);
2012 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2013 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2014 }
2016 /* ry */
2017 {
2018 eact = create_adjustment_action( "RadiusYAction",
2019 _("Ry:"), _("Vertical radius of rounded corners"),
2020 "tools.shapes.rect", "ry", 0,
2021 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2022 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2023 0, 0, 0,
2024 sp_rtb_ry_value_changed);
2025 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2026 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2027 }
2029 // add the units menu
2030 {
2031 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), _("") );
2032 gtk_action_group_add_action( mainActions, act );
2033 }
2035 /* Reset */
2036 {
2037 InkAction* inky = ink_action_new( "RectResetAction",
2038 _("Not rounded"),
2039 _("Make corners sharp"),
2040 "squared_corner",
2041 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2042 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2043 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2044 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2045 g_object_set_data( holder, "not_rounded", inky );
2046 }
2048 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2049 sp_rtb_sensitivize( holder );
2051 sigc::connection *connection = new sigc::connection(
2052 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2053 );
2054 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2055 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2056 }
2058 //########################
2059 //## Spiral ##
2060 //########################
2062 static void
2063 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2064 {
2065 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2067 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2068 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2069 }
2071 // quit if run by the attr_changed listener
2072 if (g_object_get_data( tbl, "freeze" )) {
2073 return;
2074 }
2076 // in turn, prevent listener from responding
2077 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2079 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2081 bool modmade = false;
2082 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2083 items != NULL;
2084 items = items->next)
2085 {
2086 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2087 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2088 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2089 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2090 modmade = true;
2091 }
2092 }
2094 g_free(namespaced_name);
2096 if (modmade) {
2097 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2098 _("Change spiral"));
2099 }
2101 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2102 }
2104 static void
2105 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2106 {
2107 sp_spl_tb_value_changed(adj, tbl, "revolution");
2108 }
2110 static void
2111 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2112 {
2113 sp_spl_tb_value_changed(adj, tbl, "expansion");
2114 }
2116 static void
2117 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2118 {
2119 sp_spl_tb_value_changed(adj, tbl, "t0");
2120 }
2122 static void
2123 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
2124 {
2125 GtkWidget *tbl = GTK_WIDGET(obj);
2127 GtkAdjustment *adj;
2129 // fixme: make settable
2130 gdouble rev = 5;
2131 gdouble exp = 1.0;
2132 gdouble t0 = 0.0;
2134 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2135 gtk_adjustment_set_value(adj, rev);
2136 gtk_adjustment_value_changed(adj);
2138 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2139 gtk_adjustment_set_value(adj, exp);
2140 gtk_adjustment_value_changed(adj);
2142 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2143 gtk_adjustment_set_value(adj, t0);
2144 gtk_adjustment_value_changed(adj);
2146 spinbutton_defocus(GTK_OBJECT(tbl));
2147 }
2150 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2151 gchar const *old_value, gchar const *new_value,
2152 bool is_interactive, gpointer data)
2153 {
2154 GtkWidget *tbl = GTK_WIDGET(data);
2156 // quit if run by the _changed callbacks
2157 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2158 return;
2159 }
2161 // in turn, prevent callbacks from responding
2162 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2164 GtkAdjustment *adj;
2165 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2166 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2168 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2169 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2171 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2172 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2174 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2175 }
2178 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2179 NULL, /* child_added */
2180 NULL, /* child_removed */
2181 spiral_tb_event_attr_changed,
2182 NULL, /* content_changed */
2183 NULL /* order_changed */
2184 };
2186 static void
2187 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2188 {
2189 int n_selected = 0;
2190 Inkscape::XML::Node *repr = NULL;
2192 purge_repr_listener( tbl, tbl );
2194 for (GSList const *items = selection->itemList();
2195 items != NULL;
2196 items = items->next)
2197 {
2198 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2199 n_selected++;
2200 repr = SP_OBJECT_REPR((SPItem *) items->data);
2201 }
2202 }
2204 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2206 if (n_selected == 0) {
2207 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2208 } else if (n_selected == 1) {
2209 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2211 if (repr) {
2212 g_object_set_data( tbl, "repr", repr );
2213 Inkscape::GC::anchor(repr);
2214 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2215 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2216 }
2217 } else {
2218 // FIXME: implement averaging of all parameters for multiple selected
2219 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2220 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2221 }
2222 }
2225 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2226 {
2227 EgeAdjustmentAction* eact = 0;
2229 {
2230 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2231 ege_output_action_set_use_markup( act, TRUE );
2232 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2233 g_object_set_data( holder, "mode_action", act );
2234 }
2236 /* Revolution */
2237 {
2238 eact = create_adjustment_action( "SpiralRevolutionAction",
2239 _("Turns:"), _("Number of revolutions"),
2240 "tools.shapes.spiral", "revolution", 3.0,
2241 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2242 0.01, 1024.0, 0.1, 1.0,
2243 0, 0, 0,
2244 sp_spl_tb_revolution_value_changed, 1, 2);
2245 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2246 }
2248 /* Expansion */
2249 {
2250 eact = create_adjustment_action( "SpiralExpansionAction",
2251 _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2252 "tools.shapes.spiral", "expansion", 1.0,
2253 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2254 0.0, 1000.0, 0.01, 1.0,
2255 0, 0, 0,
2256 sp_spl_tb_expansion_value_changed);
2257 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2258 }
2260 /* T0 */
2261 {
2262 eact = create_adjustment_action( "SpiralT0Action",
2263 _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2264 "tools.shapes.spiral", "t0", 0.0,
2265 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2266 0.0, 0.999, 0.01, 1.0,
2267 0, 0, 0,
2268 sp_spl_tb_t0_value_changed);
2269 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2270 }
2272 /* Reset */
2273 {
2274 InkAction* inky = ink_action_new( "SpiralResetAction",
2275 _("Defaults"),
2276 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2277 GTK_STOCK_CLEAR,
2278 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2279 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2280 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2281 }
2284 sigc::connection *connection = new sigc::connection(
2285 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2286 );
2287 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2288 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2289 }
2291 //########################
2292 //## Pen/Pencil ##
2293 //########################
2296 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2297 {
2298 // Put stuff here
2299 }
2301 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2302 {
2303 // Put stuff here
2304 }
2307 //########################
2308 //## Calligraphy ##
2309 //########################
2311 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
2312 {
2313 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
2314 }
2316 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
2317 {
2318 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
2319 }
2321 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
2322 {
2323 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
2324 }
2326 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
2327 {
2328 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
2329 }
2331 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
2332 {
2333 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
2334 }
2336 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
2337 {
2338 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
2339 }
2341 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
2342 {
2343 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
2344 }
2346 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
2347 {
2348 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
2349 }
2351 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer data )
2352 {
2353 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2354 }
2356 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer data )
2357 {
2358 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
2359 }
2361 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
2362 {
2363 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2365 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
2366 }
2368 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
2369 {
2370 // FIXME: make defaults settable via Inkscape Options
2371 struct KeyValue {
2372 char const *key;
2373 double value;
2374 } const key_values[] = {
2375 {"mass", 0.02},
2376 {"wiggle", 0.0},
2377 {"angle", 30.0},
2378 {"width", 15},
2379 {"thinning", 0.1},
2380 {"tremor", 0.0},
2381 {"flatness", 0.9},
2382 {"cap_rounding", 0.0}
2383 };
2385 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2386 KeyValue const &kv = key_values[i];
2387 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
2388 if ( adj ) {
2389 gtk_adjustment_set_value(adj, kv.value);
2390 }
2391 }
2392 }
2395 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2396 {
2397 {
2398 EgeAdjustmentAction* calligraphy_angle = 0;
2400 {
2401 /* Width */
2402 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
2403 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2404 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
2405 _("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2406 "tools.calligraphic", "width", 15,
2407 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
2408 1, 100, 1.0, 10.0,
2409 labels, values, G_N_ELEMENTS(labels),
2410 sp_ddc_width_value_changed, 0.01, 0, 100 );
2411 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2412 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2413 }
2415 {
2416 /* Thinning */
2417 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
2418 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
2419 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
2420 _("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2421 "tools.calligraphic", "thinning", 0.1,
2422 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2423 -1.0, 1.0, 0.01, 0.1,
2424 labels, values, G_N_ELEMENTS(labels),
2425 sp_ddc_velthin_value_changed, 0.01, 2);
2426 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2427 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2428 }
2430 {
2431 /* Angle */
2432 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
2433 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2434 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
2435 _("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2436 "tools.calligraphic", "angle", 30,
2437 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
2438 -90.0, 90.0, 1.0, 10.0,
2439 labels, values, G_N_ELEMENTS(labels),
2440 sp_ddc_angle_value_changed, 1, 0 );
2441 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2442 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2443 calligraphy_angle = eact;
2444 }
2446 {
2447 /* Fixation */
2448 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
2449 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
2450 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
2451 _("Fixation:"), _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
2452 "tools.calligraphic", "flatness", 0.9,
2453 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2454 0.0, 1.0, 0.01, 0.1,
2455 labels, values, G_N_ELEMENTS(labels),
2456 sp_ddc_flatness_value_changed, 0.01, 2 );
2457 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2458 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2459 }
2461 {
2462 /* Cap Rounding */
2463 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
2464 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
2465 // TRANSLATORS: "cap" means "end" (both start and finish) here
2466 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
2467 _("Caps:"), _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
2468 "tools.calligraphic", "cap_rounding", 0.0,
2469 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2470 0.0, 5.0, 0.01, 0.1,
2471 labels, values, G_N_ELEMENTS(labels),
2472 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
2473 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2474 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2475 }
2477 {
2478 /* Tremor */
2479 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
2480 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
2481 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
2482 _("Tremor:"), _("Increase to make strokes rugged and trembling"),
2483 "tools.calligraphic", "tremor", 0.0,
2484 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2485 0.0, 1.0, 0.01, 0.1,
2486 labels, values, G_N_ELEMENTS(labels),
2487 sp_ddc_tremor_value_changed, 0.01, 2 );
2489 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2490 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2491 }
2493 {
2494 /* Wiggle */
2495 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
2496 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
2497 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
2498 _("Wiggle:"), _("Increase to make the pen waver and wiggle"),
2499 "tools.calligraphic", "wiggle", 0.0,
2500 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2501 0.0, 1.0, 0.01, 0.1,
2502 labels, values, G_N_ELEMENTS(labels),
2503 sp_ddc_wiggle_value_changed, 0.01, 2 );
2504 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2505 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2506 }
2508 {
2509 /* Mass */
2510 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
2511 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
2512 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
2513 _("Mass:"), _("Increase to make the pen drag behind, as if slowed by inertia"),
2514 "tools.calligraphic", "mass", 0.02,
2515 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2516 0.0, 1.0, 0.01, 0.1,
2517 labels, values, G_N_ELEMENTS(labels),
2518 sp_ddc_mass_value_changed, 0.01, 2 );
2519 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2520 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2521 }
2524 /* Trace Background button */
2525 {
2526 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
2527 _("Trace Background"),
2528 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
2529 "trace_background",
2530 Inkscape::ICON_SIZE_DECORATION );
2531 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2532 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
2533 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
2534 }
2536 /* Use Pressure button */
2537 {
2538 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
2539 _("Pressure"),
2540 _("Use the pressure of the input device to alter the width of the pen"),
2541 "use_pressure",
2542 Inkscape::ICON_SIZE_DECORATION );
2543 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2544 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
2545 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
2546 }
2548 /* Use Tilt button */
2549 {
2550 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
2551 _("Tilt"),
2552 _("Use the tilt of the input device to alter the angle of the pen's nib"),
2553 "use_tilt",
2554 Inkscape::ICON_SIZE_DECORATION );
2555 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2556 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
2557 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2558 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2559 }
2561 /* Reset */
2562 {
2563 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
2564 _("Defaults"),
2565 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2566 GTK_STOCK_CLEAR );
2567 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
2568 gtk_action_group_add_action( mainActions, act );
2569 gtk_action_set_sensitive( act, TRUE );
2570 }
2571 }
2572 }
2575 //########################
2576 //## Circle / Arc ##
2577 //########################
2579 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
2580 {
2581 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
2582 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
2584 if (v1 == 0 && v2 == 0) {
2585 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
2586 gtk_action_set_sensitive( ocb, FALSE );
2587 gtk_action_set_sensitive( make_whole, FALSE );
2588 }
2589 } else {
2590 gtk_action_set_sensitive( ocb, TRUE );
2591 gtk_action_set_sensitive( make_whole, TRUE );
2592 }
2593 }
2595 static void
2596 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
2597 {
2598 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2600 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2601 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2602 }
2604 // quit if run by the attr_changed listener
2605 if (g_object_get_data( tbl, "freeze" )) {
2606 return;
2607 }
2609 // in turn, prevent listener from responding
2610 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2612 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2614 bool modmade = false;
2615 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2616 items != NULL;
2617 items = items->next)
2618 {
2619 SPItem *item = SP_ITEM(items->data);
2621 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2623 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2624 SPArc *arc = SP_ARC(item);
2626 if (!strcmp(value_name, "start"))
2627 ge->start = (adj->value * M_PI)/ 180;
2628 else
2629 ge->end = (adj->value * M_PI)/ 180;
2631 sp_genericellipse_normalize(ge);
2632 ((SPObject *)arc)->updateRepr();
2633 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2635 modmade = true;
2636 }
2637 }
2639 g_free(namespaced_name);
2641 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
2643 sp_arctb_sensitivize( tbl, adj->value, other->value );
2645 if (modmade) {
2646 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
2647 _("Arc: Change start/end"));
2648 }
2650 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2651 }
2654 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
2655 {
2656 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
2657 }
2659 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
2660 {
2661 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
2662 }
2664 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
2665 {
2666 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2667 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2668 if ( ege_select_one_action_get_active( act ) != 0 ) {
2669 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2670 } else {
2671 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2672 }
2673 }
2675 // quit if run by the attr_changed listener
2676 if (g_object_get_data( tbl, "freeze" )) {
2677 return;
2678 }
2680 // in turn, prevent listener from responding
2681 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2683 bool modmade = false;
2685 if ( ege_select_one_action_get_active(act) != 0 ) {
2686 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2687 items != NULL;
2688 items = items->next)
2689 {
2690 if (SP_IS_ARC((SPItem *) items->data)) {
2691 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2692 repr->setAttribute("sodipodi:open", "true");
2693 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2694 modmade = true;
2695 }
2696 }
2697 } else {
2698 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2699 items != NULL;
2700 items = items->next)
2701 {
2702 if (SP_IS_ARC((SPItem *) items->data)) {
2703 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2704 repr->setAttribute("sodipodi:open", NULL);
2705 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2706 modmade = true;
2707 }
2708 }
2709 }
2711 if (modmade) {
2712 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
2713 _("Arc: Change open/closed"));
2714 }
2716 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2717 }
2719 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
2720 {
2721 GtkAdjustment *adj;
2722 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
2723 gtk_adjustment_set_value(adj, 0.0);
2724 gtk_adjustment_value_changed(adj);
2726 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
2727 gtk_adjustment_set_value(adj, 0.0);
2728 gtk_adjustment_value_changed(adj);
2730 spinbutton_defocus( GTK_OBJECT(obj) );
2731 }
2733 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2734 gchar const *old_value, gchar const *new_value,
2735 bool is_interactive, gpointer data)
2736 {
2737 GObject *tbl = G_OBJECT(data);
2739 // quit if run by the _changed callbacks
2740 if (g_object_get_data( tbl, "freeze" )) {
2741 return;
2742 }
2744 // in turn, prevent callbacks from responding
2745 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2747 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2748 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2750 GtkAdjustment *adj1,*adj2;
2751 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
2752 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2753 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
2754 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2756 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
2758 char const *openstr = NULL;
2759 openstr = repr->attribute("sodipodi:open");
2760 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
2762 if (openstr) {
2763 ege_select_one_action_set_active( ocb, 1 );
2764 } else {
2765 ege_select_one_action_set_active( ocb, 0 );
2766 }
2768 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2769 }
2771 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2772 NULL, /* child_added */
2773 NULL, /* child_removed */
2774 arc_tb_event_attr_changed,
2775 NULL, /* content_changed */
2776 NULL /* order_changed */
2777 };
2780 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2781 {
2782 int n_selected = 0;
2783 Inkscape::XML::Node *repr = NULL;
2785 purge_repr_listener( tbl, tbl );
2787 for (GSList const *items = selection->itemList();
2788 items != NULL;
2789 items = items->next)
2790 {
2791 if (SP_IS_ARC((SPItem *) items->data)) {
2792 n_selected++;
2793 repr = SP_OBJECT_REPR((SPItem *) items->data);
2794 }
2795 }
2797 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2799 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2800 if (n_selected == 0) {
2801 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2802 } else if (n_selected == 1) {
2803 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2804 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2806 if (repr) {
2807 g_object_set_data( tbl, "repr", repr );
2808 Inkscape::GC::anchor(repr);
2809 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2810 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2811 }
2812 } else {
2813 // FIXME: implement averaging of all parameters for multiple selected
2814 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2815 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2816 sp_arctb_sensitivize( tbl, 1, 0 );
2817 }
2818 }
2821 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2822 {
2823 EgeAdjustmentAction* eact = 0;
2826 {
2827 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
2828 ege_output_action_set_use_markup( act, TRUE );
2829 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2830 g_object_set_data( holder, "mode_action", act );
2831 }
2833 /* Start */
2834 {
2835 eact = create_adjustment_action( "ArcStartAction",
2836 _("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2837 "tools.shapes.arc", "start", 0.0,
2838 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
2839 -360.0, 360.0, 1.0, 10.0,
2840 0, 0, 0,
2841 sp_arctb_start_value_changed);
2842 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2843 }
2845 /* End */
2846 {
2847 eact = create_adjustment_action( "ArcEndAction",
2848 _("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2849 "tools.shapes.arc", "end", 0.0,
2850 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2851 -360.0, 360.0, 1.0, 10.0,
2852 0, 0, 0,
2853 sp_arctb_end_value_changed);
2854 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2855 }
2857 /* Segments / Pie checkbox */
2858 {
2859 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2861 GtkTreeIter iter;
2862 gtk_list_store_append( model, &iter );
2863 gtk_list_store_set( model, &iter,
2864 0, _("Closed arc"),
2865 1, _("Switch to segment (closed shape with two radii)"),
2866 2, "circle_closed_arc",
2867 -1 );
2869 gtk_list_store_append( model, &iter );
2870 gtk_list_store_set( model, &iter,
2871 0, _("Open Arc"),
2872 1, _("Switch to arc (unclosed shape)"),
2873 2, "circle_open_arc",
2874 -1 );
2876 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
2877 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2878 g_object_set_data( holder, "open_action", act );
2880 ege_select_one_action_set_appearance( act, "full" );
2881 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2882 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2883 ege_select_one_action_set_icon_column( act, 2 );
2884 ege_select_one_action_set_tooltip_column( act, 1 );
2886 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2887 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
2888 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
2889 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
2890 }
2892 /* Make Whole */
2893 {
2894 InkAction* inky = ink_action_new( "ArcResetAction",
2895 _("Make whole"),
2896 _("Make the shape a whole ellipse, not arc or segment"),
2897 "reset_circle",
2898 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2899 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
2900 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2901 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2902 g_object_set_data( holder, "make_whole", inky );
2903 }
2905 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
2906 // sensitivize make whole and open checkbox
2907 {
2908 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
2909 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
2910 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
2911 }
2914 sigc::connection *connection = new sigc::connection(
2915 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
2916 );
2917 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2918 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2919 }
2924 // toggle button callbacks and updaters
2926 //########################
2927 //## Dropper ##
2928 //########################
2930 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
2931 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
2932 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
2933 if ( set_action ) {
2934 if ( gtk_toggle_action_get_active( act ) ) {
2935 gtk_action_set_sensitive( set_action, TRUE );
2936 } else {
2937 gtk_action_set_sensitive( set_action, FALSE );
2938 }
2939 }
2941 spinbutton_defocus(GTK_OBJECT(tbl));
2942 }
2944 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
2945 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2946 spinbutton_defocus(GTK_OBJECT(tbl));
2947 }
2950 /**
2951 * Dropper auxiliary toolbar construction and setup.
2952 *
2953 * TODO: Would like to add swatch of current color.
2954 * TODO: Add queue of last 5 or so colors selected with new swatches so that
2955 * can drag and drop places. Will provide a nice mixing palette.
2956 */
2957 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2958 {
2959 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
2961 {
2962 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
2963 _("Pick alpha"),
2964 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
2965 "color_alpha_get",
2966 Inkscape::ICON_SIZE_DECORATION );
2967 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2968 g_object_set_data( holder, "pick_action", act );
2969 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
2970 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
2971 }
2973 {
2974 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
2975 _("Set alpha"),
2976 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
2977 "color_alpha_set",
2978 Inkscape::ICON_SIZE_DECORATION );
2979 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2980 g_object_set_data( holder, "set_action", act );
2981 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
2982 // make sure it's disabled if we're not picking alpha
2983 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
2984 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
2985 }
2986 }
2989 //########################
2990 //## Text Toolbox ##
2991 //########################
2992 /*
2993 static void
2994 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2995 {
2996 //Call back for letter sizing spinbutton
2997 }
2999 static void
3000 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3001 {
3002 //Call back for line height spinbutton
3003 }
3005 static void
3006 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3007 {
3008 //Call back for horizontal kerning spinbutton
3009 }
3011 static void
3012 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3013 {
3014 //Call back for vertical kerning spinbutton
3015 }
3017 static void
3018 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3019 {
3020 //Call back for letter rotation spinbutton
3021 }*/
3023 namespace {
3025 bool visible = false;
3027 void
3028 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
3029 {
3031 SPStyle *query =
3032 sp_style_new ();
3034 int result_family =
3035 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3037 int result_style =
3038 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3040 int result_numbers =
3041 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3043 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3045 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3046 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3047 {
3048 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3050 if (repr)
3051 {
3052 sp_style_read_from_repr (query, repr);
3053 }
3054 else
3055 {
3056 return;
3057 }
3058 }
3060 if (query->text)
3061 {
3062 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3063 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3064 gtk_entry_set_text (GTK_ENTRY (entry), "");
3066 } else if (query->text->font_family.value) {
3068 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3069 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3071 Gtk::TreePath path;
3072 try {
3073 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3074 } catch (...) {
3075 return;
3076 }
3078 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3079 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3081 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3083 gtk_tree_selection_select_path (tselection, path.gobj());
3084 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3086 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3087 }
3089 //Size
3090 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3091 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3092 g_object_set_data (tbl, "size-block", gpointer(1));
3093 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3094 g_object_set_data (tbl, "size-block", gpointer(0));
3095 free (str);
3097 //Anchor
3098 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3099 {
3100 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3101 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3102 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3103 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3104 }
3105 else
3106 {
3107 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3108 {
3109 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3110 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3111 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3112 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3113 }
3114 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3115 {
3116 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3117 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3118 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3119 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3120 }
3121 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3122 {
3123 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3124 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3125 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3126 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3127 }
3128 }
3130 //Style
3131 {
3132 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3134 gboolean active = gtk_toggle_button_get_active (button);
3135 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3137 if (active != check)
3138 {
3139 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3140 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3141 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3142 }
3143 }
3145 {
3146 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3148 gboolean active = gtk_toggle_button_get_active (button);
3149 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3151 if (active != check)
3152 {
3153 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3154 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3155 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3156 }
3157 }
3159 //Orientation
3160 //locking both buttons, changing one affect all group (both)
3161 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3162 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3164 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3165 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3167 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3168 {
3169 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3170 }
3171 else
3172 {
3173 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3174 }
3175 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3176 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3177 }
3178 }
3180 void
3181 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
3182 {
3183 sp_text_toolbox_selection_changed (selection, tbl);
3184 }
3186 void
3187 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3188 {
3189 sp_text_toolbox_selection_changed (NULL, tbl);
3190 }
3192 void
3193 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
3194 GObject *tbl)
3195 {
3196 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3197 GtkTreeModel *model = 0;
3198 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3199 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3200 GtkTreeIter iter;
3201 char *family = 0;
3203 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3204 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3206 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3207 return;
3208 }
3210 gtk_tree_model_get (model, &iter, 0, &family, -1);
3212 if (g_object_get_data (G_OBJECT (selection), "block"))
3213 {
3214 gtk_entry_set_text (GTK_ENTRY (entry), family);
3215 return;
3216 }
3218 gtk_widget_hide (popdown);
3219 visible = false;
3221 gtk_entry_set_text (GTK_ENTRY (entry), family);
3223 SPStyle *query =
3224 sp_style_new ();
3226 int result_numbers =
3227 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3229 SPCSSAttr *css = sp_repr_css_attr_new ();
3230 sp_repr_css_set_property (css, "font-family", family);
3232 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3233 if (result_numbers == QUERY_STYLE_NOTHING)
3234 {
3235 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3236 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3237 }
3238 else
3239 {
3240 sp_desktop_set_style (desktop, css, true, true);
3241 }
3243 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3244 _("Text: Change font family"));
3245 sp_repr_css_attr_unref (css);
3246 free (family);
3247 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3249 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3250 }
3252 void
3253 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
3254 GObject *tbl)
3255 {
3256 const char *family = gtk_entry_get_text (entry);
3258 try {
3259 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3260 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3261 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3262 gtk_tree_selection_select_path (selection, path.gobj());
3263 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3264 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3265 } catch (...) {
3266 if (family && strlen (family))
3267 {
3268 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3269 }
3270 }
3271 }
3273 void
3274 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
3275 gpointer data)
3276 {
3277 if (g_object_get_data (G_OBJECT (button), "block")) return;
3278 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3279 int prop = GPOINTER_TO_INT(data);
3281 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3282 SPCSSAttr *css = sp_repr_css_attr_new ();
3284 switch (prop)
3285 {
3286 case 0:
3287 {
3288 sp_repr_css_set_property (css, "text-anchor", "start");
3289 sp_repr_css_set_property (css, "text-align", "start");
3290 break;
3291 }
3292 case 1:
3293 {
3294 sp_repr_css_set_property (css, "text-anchor", "middle");
3295 sp_repr_css_set_property (css, "text-align", "center");
3296 break;
3297 }
3299 case 2:
3300 {
3301 sp_repr_css_set_property (css, "text-anchor", "end");
3302 sp_repr_css_set_property (css, "text-align", "end");
3303 break;
3304 }
3306 case 3:
3307 {
3308 sp_repr_css_set_property (css, "text-anchor", "start");
3309 sp_repr_css_set_property (css, "text-align", "justify");
3310 break;
3311 }
3312 }
3314 SPStyle *query =
3315 sp_style_new ();
3316 int result_numbers =
3317 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3319 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3320 if (result_numbers == QUERY_STYLE_NOTHING)
3321 {
3322 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3323 }
3325 sp_desktop_set_style (desktop, css, true, true);
3326 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3327 _("Text: Change alignment"));
3328 sp_repr_css_attr_unref (css);
3330 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3331 }
3333 void
3334 sp_text_toolbox_style_toggled (GtkToggleButton *button,
3335 gpointer data)
3336 {
3337 if (g_object_get_data (G_OBJECT (button), "block")) return;
3339 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3340 SPCSSAttr *css = sp_repr_css_attr_new ();
3341 int prop = GPOINTER_TO_INT(data);
3342 bool active = gtk_toggle_button_get_active (button);
3345 switch (prop)
3346 {
3347 case 0:
3348 {
3349 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
3350 break;
3351 }
3353 case 1:
3354 {
3355 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
3356 break;
3357 }
3358 }
3360 SPStyle *query =
3361 sp_style_new ();
3362 int result_numbers =
3363 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3365 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3366 if (result_numbers == QUERY_STYLE_NOTHING)
3367 {
3368 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3369 }
3371 sp_desktop_set_style (desktop, css, true, true);
3372 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3373 _("Text: Change font style"));
3374 sp_repr_css_attr_unref (css);
3376 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3377 }
3379 void
3380 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
3381 gpointer data)
3382 {
3383 if (g_object_get_data (G_OBJECT (button), "block")) {
3384 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3385 return;
3386 }
3388 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3389 SPCSSAttr *css = sp_repr_css_attr_new ();
3390 int prop = GPOINTER_TO_INT(data);
3392 switch (prop)
3393 {
3394 case 0:
3395 {
3396 sp_repr_css_set_property (css, "writing-mode", "lr");
3397 break;
3398 }
3400 case 1:
3401 {
3402 sp_repr_css_set_property (css, "writing-mode", "tb");
3403 break;
3404 }
3405 }
3407 SPStyle *query =
3408 sp_style_new ();
3409 int result_numbers =
3410 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3412 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3413 if (result_numbers == QUERY_STYLE_NOTHING)
3414 {
3415 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3416 }
3418 sp_desktop_set_style (desktop, css, true, true);
3419 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3420 _("Text: Change orientation"));
3421 sp_repr_css_attr_unref (css);
3423 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3424 }
3426 gboolean
3427 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3428 {
3429 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3430 if (!desktop) return FALSE;
3432 switch (get_group0_keyval (event)) {
3433 case GDK_Escape: // defocus
3434 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3435 return TRUE; // I consumed the event
3436 break;
3437 case GDK_Return: // defocus
3438 case GDK_KP_Enter:
3439 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3440 return TRUE; // I consumed the event
3441 break;
3442 }
3443 return FALSE;
3444 }
3446 gboolean
3447 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3448 {
3449 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3450 if (!desktop) return FALSE;
3452 switch (get_group0_keyval (event)) {
3453 case GDK_Escape: // defocus
3454 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3455 sp_text_toolbox_selection_changed (NULL, tbl); // update
3456 return TRUE; // I consumed the event
3457 break;
3458 }
3459 return FALSE;
3460 }
3462 gboolean
3463 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3464 {
3465 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3466 if (!desktop) return FALSE;
3468 switch (get_group0_keyval (event)) {
3469 case GDK_Escape: // defocus
3470 gtk_widget_hide (w);
3471 visible = false;
3472 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3473 return TRUE; // I consumed the event
3474 break;
3475 }
3476 return FALSE;
3477 }
3480 void
3481 sp_text_toolbox_size_changed (GtkComboBox *cbox,
3482 GObject *tbl)
3483 {
3484 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3486 if (g_object_get_data (tbl, "size-block")) return;
3488 #if GTK_CHECK_VERSION(2,6,0)
3489 char *text = gtk_combo_box_get_active_text (cbox);
3490 #else // GTK_CHECK_VERSION(2,6,0)
3491 GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3492 GtkTreeIter iter;
3493 char *text = NULL;
3495 if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3496 gtk_tree_model_get (model, &iter, 0, &text, -1);
3497 #endif // GTK_CHECK_VERSION(2,6,0)
3499 SPCSSAttr *css = sp_repr_css_attr_new ();
3500 sp_repr_css_set_property (css, "font-size", text);
3501 free (text);
3503 SPStyle *query =
3504 sp_style_new ();
3505 int result_numbers =
3506 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3508 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3509 if (result_numbers == QUERY_STYLE_NOTHING)
3510 {
3511 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3512 }
3514 sp_desktop_set_style (desktop, css, true, true);
3515 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
3516 _("Text: Change font size"));
3517 sp_repr_css_attr_unref (css);
3520 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3521 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3522 }
3524 void
3525 sp_text_toolbox_text_popdown_clicked (GtkButton *button,
3526 GObject *tbl)
3527 {
3528 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3529 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3530 int x, y;
3532 if (!visible)
3533 {
3534 gdk_window_get_origin (widget->window, &x, &y);
3535 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
3536 gtk_widget_show_all (popdown);
3538 gdk_pointer_grab (widget->window, TRUE,
3539 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3540 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3541 GDK_POINTER_MOTION_MASK),
3542 NULL, NULL, GDK_CURRENT_TIME);
3544 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3546 visible = true;
3547 }
3548 else
3549 {
3550 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3551 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3552 gtk_widget_hide (popdown);
3553 visible = false;
3554 }
3555 }
3557 gboolean
3558 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
3559 GdkEventFocus *event,
3560 GObject *tbl)
3561 {
3562 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3563 return FALSE;
3564 }
3566 gboolean
3567 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
3568 GdkEventFocus *event,
3569 GObject *tbl)
3570 {
3571 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3573 gtk_widget_hide (popdown);
3574 visible = false;
3575 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3576 return TRUE;
3577 }
3579 void
3580 cell_data_func (GtkTreeViewColumn *column,
3581 GtkCellRenderer *cell,
3582 GtkTreeModel *tree_model,
3583 GtkTreeIter *iter,
3584 gpointer data)
3585 {
3586 char *family,
3587 *family_escaped,
3588 *sample_escaped;
3590 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3592 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3594 family_escaped = g_markup_escape_text (family, -1);
3595 sample_escaped = g_markup_escape_text (sample, -1);
3597 std::stringstream markup;
3598 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3599 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3601 free (family);
3602 free (family_escaped);
3603 free (sample_escaped);
3604 }
3606 static void delete_completion(GObject *obj, GtkWidget *entry) {
3607 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3608 if (completion) {
3609 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3610 g_object_unref (completion);
3611 }
3612 }
3614 GtkWidget*
3615 sp_text_toolbox_new (SPDesktop *desktop)
3616 {
3617 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
3619 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3620 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3622 GtkTooltips *tt = gtk_tooltips_new();
3623 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3625 ////////////Family
3626 //Window
3627 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3628 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3630 //Entry
3631 GtkWidget *entry = gtk_entry_new ();
3632 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3633 GtkEntryCompletion *completion = gtk_entry_completion_new ();
3634 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3635 gtk_entry_completion_set_text_column (completion, 0);
3636 gtk_entry_completion_set_minimum_key_length (completion, 1);
3637 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3638 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3639 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
3640 aux_toolbox_space (tbl, 1);
3641 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3642 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
3644 //Button
3645 GtkWidget *button = gtk_button_new ();
3646 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3647 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3649 //Popdown
3650 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
3651 GtkWidget *treeview = gtk_tree_view_new ();
3653 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
3654 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
3655 gtk_tree_view_column_pack_start (column, cell, FALSE);
3656 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3657 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3658 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3660 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3661 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3662 #if GTK_CHECK_VERSION(2,6,0)
3663 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3664 #endif // GTK_CHECK_VERSION(2,6,0)
3666 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3668 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
3669 gtk_container_add (GTK_CONTAINER (sw), treeview);
3671 gtk_container_add (GTK_CONTAINER (window), sw);
3672 gtk_widget_set_size_request (window, 300, 450);
3674 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3675 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3676 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3678 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3680 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3681 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3683 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3684 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3686 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3687 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3688 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3689 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3690 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3692 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3693 aux_toolbox_space (tbl, 1);
3694 GtkWidget *box = gtk_event_box_new ();
3695 gtk_container_add (GTK_CONTAINER (box), image);
3696 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3697 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3698 GtkTooltips *tooltips = gtk_tooltips_new ();
3699 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3700 gtk_widget_hide (GTK_WIDGET (box));
3701 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3703 ////////////Size
3704 const char *sizes[] = {
3705 "4", "6", "8", "9", "10", "11", "12", "13", "14",
3706 "16", "18", "20", "22", "24", "28",
3707 "32", "36", "40", "48", "56", "64", "72", "144"
3708 };
3710 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3711 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3712 gtk_widget_set_size_request (cbox, 80, -1);
3713 aux_toolbox_space (tbl, 1);
3714 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3715 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3716 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3717 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3719 //spacer
3720 aux_toolbox_space (tbl, 4);
3721 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3723 ////////////Text anchor
3724 GtkWidget *group = gtk_radio_button_new (NULL);
3725 GtkWidget *row = gtk_hbox_new (FALSE, 4);
3726 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3728 // left
3729 GtkWidget *rbutton = group;
3730 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3731 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3732 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3734 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3735 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
3736 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3737 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3739 // center
3740 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3741 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3742 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3743 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3745 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3746 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
3747 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
3748 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3750 // right
3751 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3752 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3753 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3754 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3756 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3757 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
3758 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3759 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3761 // fill
3762 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3763 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3764 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3765 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3767 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3768 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
3769 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3770 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3772 aux_toolbox_space (tbl, 1);
3773 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3775 //spacer
3776 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3778 ////////////Text style
3779 row = gtk_hbox_new (FALSE, 4);
3781 // bold
3782 rbutton = gtk_toggle_button_new ();
3783 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3784 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3785 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3786 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3788 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3789 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
3790 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3792 // italic
3793 rbutton = gtk_toggle_button_new ();
3794 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3795 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3796 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3797 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3799 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3800 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
3801 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
3803 aux_toolbox_space (tbl, 1);
3804 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3806 //spacer
3807 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3809 ////////////Text orientation
3810 group = gtk_radio_button_new (NULL);
3811 row = gtk_hbox_new (FALSE, 4);
3812 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3814 // horizontal
3815 rbutton = group;
3816 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3817 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
3818 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3819 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3821 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3822 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3823 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3825 // vertical
3826 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3827 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3828 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
3829 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3830 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3832 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3833 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
3834 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
3835 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3838 //watch selection
3839 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3841 sigc::connection *c_selection_changed =
3842 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
3843 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3844 pool->add_connection ("selection-changed", c_selection_changed);
3846 sigc::connection *c_selection_modified =
3847 new sigc::connection (sp_desktop_selection (desktop)->connectModified
3848 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3849 pool->add_connection ("selection-modified", c_selection_modified);
3851 sigc::connection *c_subselection_changed =
3852 new sigc::connection (desktop->connectToolSubselectionChanged
3853 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3854 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3856 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3859 #if 0
3860 // horizontal
3861 {
3862 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3863 GtkWidget *b = group = gtk_radio_button_new (NULL);
3864 gtk_container_add (GTK_CONTAINER (b), px);
3865 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3866 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3867 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3868 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3869 }
3871 // vertical
3872 {
3873 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3874 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3875 gtk_container_add (GTK_CONTAINER (b), px);
3876 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3877 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3878 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3879 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3880 }
3882 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3884 // letter spacing
3885 {
3886 {
3887 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3888 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3889 gtk_container_add (GTK_CONTAINER (hb), image);
3890 gtk_widget_show(image);
3891 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3892 }
3894 {
3895 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3896 "tools.text", "letter_spacing", 0.0,
3897 us, tbl, FALSE, NULL,
3898 -1000.0, 1000.0, 0.1, 0.1,
3899 sp_text_letter_changed, 0.1, 1);
3900 gtk_widget_set_size_request (hb, 45, 6);
3901 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3902 }
3903 }
3905 // line spacing
3906 {
3907 {
3908 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3909 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3910 gtk_container_add (GTK_CONTAINER (hb), image);
3911 gtk_widget_show(image);
3912 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3913 }
3915 {
3916 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3917 "tools.text", "line_spacing", 0,
3918 us, tbl, FALSE, NULL,
3919 -1000.0, 1000.0, 0.1, 0.1,
3920 sp_text_line_changed, 0.1, 1);
3921 gtk_widget_set_size_request (hb, 45, 0);
3922 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3923 }
3924 }
3926 {
3927 // horizontal kerning/vertical kerning units menu: create
3928 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3929 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3930 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3932 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3934 // horizontal kerning
3935 {
3936 {
3937 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3938 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3939 gtk_container_add (GTK_CONTAINER (hb), image);
3940 gtk_widget_show(image);
3941 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3942 }
3944 {
3945 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3946 "tools.text", "horizontal_kerning", 0,
3947 us, tbl, FALSE, NULL,
3948 -100.00, 100.00, 0.01, 0.1,
3949 sp_text_horiz_kern_changed);
3950 gtk_widget_set_size_request (hb, 45, 0);
3951 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3952 }
3953 }
3955 // vertical kerning
3956 {
3957 {
3958 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3959 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3960 gtk_container_add (GTK_CONTAINER (hb), image);
3961 gtk_widget_show(image);
3962 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3963 }
3965 {
3966 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3967 "tools.text", "vertical_kerning", 0,
3968 us, tbl, FALSE, NULL,
3969 -100.00, 100.00, 0.01, 0.1,
3970 sp_text_vert_kern_changed);
3971 gtk_widget_set_size_request (hb, 45, 0);
3972 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3973 }
3974 }
3976 // add the units menu
3977 gtk_widget_show(us);
3978 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3979 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3980 }
3982 // letter rotation
3983 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3984 {
3985 {
3986 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3987 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3988 gtk_container_add (GTK_CONTAINER (hb), image);
3989 gtk_widget_show(image);
3990 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3991 }
3992 {
3993 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3994 "tools.text", "letter_rotation", 0,
3995 us, tbl, FALSE, NULL,
3996 -180.0, 180.0, 0.1, 0.1,
3997 sp_text_letter_rotation_changed, 0.1, 1);
3998 gtk_widget_set_size_request (hb, 45, 0);
3999 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4000 }
4001 // rotation degree label
4002 {
4003 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4004 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4005 }
4006 }
4008 // Remove Manual Kerns
4009 {
4010 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4011 GtkWidget *button = gtk_button_new ();
4012 gtk_container_add (GTK_CONTAINER (button), px);
4013 gtk_widget_show(button);
4014 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4015 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4016 gtk_widget_set_sensitive(button, TRUE);
4017 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4018 }
4019 #endif
4021 gtk_widget_show_all (tbl);
4022 return tbl;
4024 } // end of sp_text_toolbox_new()
4026 }//<unnamed> namespace
4029 //#########################
4030 //## Connector Toolbox ##
4031 //#########################
4033 static void sp_connector_path_set_avoid(void)
4034 {
4035 cc_selection_set_avoid(true);
4036 }
4039 static void sp_connector_path_set_ignore(void)
4040 {
4041 cc_selection_set_avoid(false);
4042 }
4046 static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
4047 {
4048 // quit if run by the _changed callbacks
4049 if (g_object_get_data( tbl, "freeze" )) {
4050 return;
4051 }
4053 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
4054 SPDocument *doc = sp_desktop_document(desktop);
4056 if (!sp_document_get_undo_sensitive(doc))
4057 {
4058 return;
4059 }
4061 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4063 if ( repr->attribute("inkscape:connector-spacing") ) {
4064 gdouble priorValue = gtk_adjustment_get_value(adj);
4065 sp_repr_get_double( repr, "inkscape:connector-spacing", &priorValue );
4066 if ( priorValue == gtk_adjustment_get_value(adj) ) {
4067 return;
4068 }
4069 } else if ( adj->value == defaultConnSpacing ) {
4070 return;
4071 }
4073 // in turn, prevent callbacks from responding
4074 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
4076 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4077 SP_OBJECT(desktop->namedview)->updateRepr();
4079 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4080 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4081 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4082 NR::Matrix m = NR::identity();
4083 avoid_item_move(&m, item);
4084 }
4086 if (items) {
4087 g_slist_free(items);
4088 }
4090 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4091 _("Change connector spacing"));
4093 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
4095 spinbutton_defocus(GTK_OBJECT(tbl));
4096 }
4098 static void sp_connector_graph_layout(void)
4099 {
4100 if (!SP_ACTIVE_DESKTOP) return;
4102 // hack for clones, see comment in align-and-distribute.cpp
4103 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4104 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4106 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4108 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4110 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4111 }
4113 static void sp_directed_graph_layout_toggled( GtkToggleAction* act, GtkObject *tbl )
4114 {
4115 if ( gtk_toggle_action_get_active( act ) ) {
4116 prefs_set_string_attribute("tools.connector", "directedlayout",
4117 "true");
4118 } else {
4119 prefs_set_string_attribute("tools.connector", "directedlayout",
4120 "false");
4121 }
4122 }
4124 static void sp_nooverlaps_graph_layout_toggled( GtkToggleAction* act, GtkObject *tbl )
4125 {
4126 if ( gtk_toggle_action_get_active( act ) ) {
4127 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4128 "true");
4129 } else {
4130 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4131 "false");
4132 }
4133 }
4136 static void connector_length_changed(GtkAdjustment *adj, GObject* tbl)
4137 {
4138 prefs_set_double_attribute("tools.connector", "length", adj->value);
4139 spinbutton_defocus(GTK_OBJECT(tbl));
4140 }
4142 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4143 gchar const *name, gchar const *old_value, gchar const *new_value,
4144 bool is_interactive, gpointer data)
4145 {
4146 GtkWidget *tbl = GTK_WIDGET(data);
4148 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4149 return;
4150 }
4151 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4152 return;
4153 }
4155 GtkAdjustment *adj = (GtkAdjustment*)
4156 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4157 gdouble spacing = defaultConnSpacing;
4158 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4160 gtk_adjustment_set_value(adj, spacing);
4161 }
4164 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4165 NULL, /* child_added */
4166 NULL, /* child_removed */
4167 connector_tb_event_attr_changed,
4168 NULL, /* content_changed */
4169 NULL /* order_changed */
4170 };
4173 static void sp_connector_toolbox_prep( SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder )
4174 {
4175 {
4176 InkAction* inky = ink_action_new( "ConnectorAvoidAction",
4177 _("Avoid"),
4178 _("Make connectors avoid selected objects"),
4179 "connector_avoid",
4180 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4181 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_avoid), holder );
4182 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4183 }
4185 {
4186 InkAction* inky = ink_action_new( "ConnectorIgnoreAction",
4187 _("Ignore"),
4188 _("Make connectors ignore selected objects"),
4189 "connector_ignore",
4190 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4191 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_path_set_ignore), holder );
4192 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4193 }
4195 EgeAdjustmentAction* eact = 0;
4197 // Spacing spinbox
4198 eact = create_adjustment_action( "ConnectorSpacingAction",
4199 _("Spacing:"), _("The amount of space left around objects by auto-routing connectors"),
4200 "tools.connector", "spacing", defaultConnSpacing,
4201 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-spacing",
4202 0, 100, 1.0, 10.0,
4203 0, 0, 0,
4204 connector_spacing_changed, 1, 0 );
4205 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4207 // Graph (connector network) layout
4208 {
4209 InkAction* inky = ink_action_new( "ConnectorGraphAction",
4210 _("Graph"),
4211 _("Nicely arrange selected connector network"),
4212 "graph_layout",
4213 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
4214 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_connector_graph_layout), holder );
4215 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
4216 }
4218 // Default connector length spinbox
4219 eact = create_adjustment_action( "ConnectorLengthAction",
4220 _("Length:"), _("Ideal length for connectors when layout is applied"),
4221 "tools.connector", "length", 100,
4222 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "inkscape:connector-length",
4223 10, 1000, 10.0, 100.0,
4224 0, 0, 0,
4225 connector_length_changed, 1, 0 );
4226 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4229 // Directed edges toggle button
4230 {
4231 InkToggleAction* act = ink_toggle_action_new( "ConnectorDirectedAction",
4232 _("Downwards"),
4233 _("Make connectors with end-markers (arrows) point downwards"),
4234 "directed_graph",
4235 Inkscape::ICON_SIZE_DECORATION );
4236 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4238 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "directedlayout" );
4239 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4240 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4242 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_directed_graph_layout_toggled), holder );
4243 }
4245 // Avoid overlaps toggle button
4246 {
4247 InkToggleAction* act = ink_toggle_action_new( "ConnectorOverlapAction",
4248 _("Remove overlaps"),
4249 _("Do not allow overlapping shapes"),
4250 "remove_overlaps",
4251 Inkscape::ICON_SIZE_DECORATION );
4252 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
4254 gchar const* tbuttonstate = prefs_get_string_attribute( "tools.connector", "avoidoverlaplayout" );
4255 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act),
4256 (tbuttonstate && !strcmp(tbuttonstate, "true")) ? TRUE:FALSE );
4258 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_nooverlaps_graph_layout_toggled), holder );
4259 }
4261 // Code to watch for changes to the connector-spacing attribute in
4262 // the XML.
4263 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4264 g_assert(repr != NULL);
4266 purge_repr_listener( holder, holder );
4268 if (repr) {
4269 g_object_set_data( holder, "repr", repr );
4270 Inkscape::GC::anchor(repr);
4271 sp_repr_add_listener( repr, &connector_tb_repr_events, holder );
4272 sp_repr_synthesize_events( repr, &connector_tb_repr_events, holder );
4273 }
4274 } // end of sp_connector_toolbox_prep()
4276 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* tbl)
4277 {
4278 gint channels = ege_select_one_action_get_active( act );
4279 flood_channels_set_channels( channels );
4280 }
4282 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject *tbl)
4283 {
4284 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4285 }
4287 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
4288 {
4289 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
4290 SPUnit const *unit = tracker->getActiveUnit();
4293 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
4294 }
4296 static void paintbucket_defaults(GtkWidget *, GObject *dataKludge)
4297 {
4298 // FIXME: make defaults settable via Inkscape Options
4299 struct KeyValue {
4300 char const *key;
4301 double value;
4302 } const key_values[] = {
4303 {"threshold", 15},
4304 {"offset", 0.0}
4305 };
4307 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
4308 KeyValue const &kv = key_values[i];
4309 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
4310 if ( adj ) {
4311 gtk_adjustment_set_value(adj, kv.value);
4312 }
4313 }
4315 EgeSelectOneAction* channels_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "channels_action" ) );
4316 ege_select_one_action_set_active( channels_action, FLOOD_CHANNELS_RGB );
4317 }
4319 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4320 {
4321 EgeAdjustmentAction* eact = 0;
4323 {
4324 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4326 GList* items = 0;
4327 gint count = 0;
4328 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
4329 {
4330 GtkTreeIter iter;
4331 gtk_list_store_append( model, &iter );
4332 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4333 count++;
4334 }
4335 g_list_free( items );
4336 items = 0;
4337 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by:"), _(""), NULL, GTK_TREE_MODEL(model) );
4338 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
4339 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
4340 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
4341 g_object_set_data( holder, "channels_action", act1 );
4342 }
4344 // Spacing spinbox
4345 {
4346 eact = create_adjustment_action(
4347 "ThresholdAction",
4348 _("Threshold:"),
4349 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
4350 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
4351 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
4352 0, 0, 0,
4353 paintbucket_threshold_changed, 1, 0 );
4355 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4356 }
4358 // Create the units menu.
4359 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
4360 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
4361 g_object_set_data( holder, "tracker", tracker );
4362 {
4363 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), _("") );
4364 gtk_action_group_add_action( mainActions, act );
4365 }
4367 // Offset spinbox
4368 {
4369 eact = create_adjustment_action(
4370 "OffsetAction",
4371 _("Grow/shrink by:"),
4372 _("The amount to grow (positive) or shrink (negative) the created fill path"),
4373 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
4374 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
4375 0, 0, 0,
4376 paintbucket_offset_changed, 1, 2);
4377 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
4379 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4380 }
4382 /* Reset */
4383 {
4384 GtkAction* act = gtk_action_new( "PaintbucketResetAction",
4385 _("Defaults"),
4386 _("Reset paint bucket parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
4387 GTK_STOCK_CLEAR );
4388 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(paintbucket_defaults), holder );
4389 gtk_action_group_add_action( mainActions, act );
4390 gtk_action_set_sensitive( act, TRUE );
4391 }
4393 }
4395 /*
4396 Local Variables:
4397 mode:c++
4398 c-file-style:"stroustrup"
4399 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4400 indent-tabs-mode:nil
4401 fill-column:99
4402 End:
4403 */
4404 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :