6c3c24183c2ac12b02feec44cf00baeeaaae96ca
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 GtkWidget *sp_connector_toolbox_new(SPDesktop *desktop);
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", sp_connector_toolbox_new, 0, 0,
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 " </toolbar>"
329 " <toolbar name='DropperToolbar'>"
330 " <toolitem action='DropperPickAlphaAction' />"
331 " <toolitem action='DropperSetAlphaAction' />"
332 " </toolbar>"
333 "</ui>"
334 ;
336 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
338 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
340 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
341 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
343 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
344 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
346 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
347 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
349 /* Global text entry widgets necessary for update */
350 /* GtkWidget *dropper_rgb_entry,
351 *dropper_opacity_entry ; */
352 // should be made a private member once this is converted to class
354 static void delete_connection(GObject *obj, sigc::connection *connection) {
355 connection->disconnect();
356 delete connection;
357 }
359 static void purge_repr_listener( GObject* obj, GObject* tbl )
360 {
361 (void)obj;
362 Inkscape::XML::Node* oldrepr = reinterpret_cast<Inkscape::XML::Node *>( g_object_get_data( tbl, "repr" ) );
363 if (oldrepr) { // remove old listener
364 sp_repr_remove_listener_by_data(oldrepr, tbl);
365 Inkscape::GC::release(oldrepr);
366 oldrepr = 0;
367 g_object_set_data( tbl, "repr", NULL );
368 }
369 }
371 static GtkWidget *
372 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
373 GtkTooltips *tt, gchar const *tip)
374 {
375 GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
376 gtk_widget_show(b);
377 if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
378 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
380 return b;
381 }
383 GtkWidget *
384 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
385 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
386 Inkscape::UI::View::View *view, GtkTooltips *tt)
387 {
388 SPAction *action = verb->get_action(view);
389 if (!action) return NULL;
391 SPAction *doubleclick_action;
392 if (doubleclick_verb)
393 doubleclick_action = doubleclick_verb->get_action(view);
394 else
395 doubleclick_action = NULL;
397 /* fixme: Handle sensitive/unsensitive */
398 /* fixme: Implement sp_button_new_from_action */
399 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
400 gtk_widget_show(b);
401 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
403 return b;
404 }
406 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
407 Inkscape::UI::View::View *view, GtkTooltips *tt)
408 {
409 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
410 }
412 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
413 Inkscape::UI::View::View *view, GtkTooltips *tt)
414 {
415 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
416 }
419 static void trigger_sp_action( GtkAction* act, gpointer user_data )
420 {
421 SPAction* targetAction = SP_ACTION(user_data);
422 if ( targetAction ) {
423 sp_action_perform( targetAction, NULL );
424 }
425 }
427 static void sp_action_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data)
428 {
429 if ( data ) {
430 GtkAction* act = GTK_ACTION(data);
431 gtk_action_set_sensitive( act, sensitive );
432 }
433 }
435 static SPActionEventVector action_event_vector = {
436 {NULL},
437 NULL,
438 NULL,
439 sp_action_action_set_sensitive,
440 NULL,
441 NULL
442 };
444 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
445 {
446 GtkAction* act = 0;
448 SPAction* targetAction = verb->get_action(view);
449 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
450 act = GTK_ACTION(inky);
451 gtk_action_set_sensitive( act, targetAction->sensitive );
453 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
455 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
456 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
458 return act;
459 }
461 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
462 {
463 Inkscape::UI::View::View *view = desktop;
464 gint verbsToUse[] = {
465 // disabled until we have icons for them:
466 //find
467 //SP_VERB_EDIT_TILE,
468 //SP_VERB_EDIT_UNTILE,
469 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
470 SP_VERB_DIALOG_DISPLAY,
471 SP_VERB_DIALOG_FILL_STROKE,
472 SP_VERB_DIALOG_NAMEDVIEW,
473 SP_VERB_DIALOG_TEXT,
474 SP_VERB_DIALOG_XML_EDITOR,
475 SP_VERB_EDIT_CLONE,
476 SP_VERB_EDIT_COPY,
477 SP_VERB_EDIT_CUT,
478 SP_VERB_EDIT_DUPLICATE,
479 SP_VERB_EDIT_PASTE,
480 SP_VERB_EDIT_REDO,
481 SP_VERB_EDIT_UNDO,
482 SP_VERB_EDIT_UNLINK_CLONE,
483 SP_VERB_FILE_EXPORT,
484 SP_VERB_FILE_IMPORT,
485 SP_VERB_FILE_NEW,
486 SP_VERB_FILE_OPEN,
487 SP_VERB_FILE_PRINT,
488 SP_VERB_FILE_SAVE,
489 SP_VERB_OBJECT_TO_CURVE,
490 SP_VERB_SELECTION_GROUP,
491 SP_VERB_SELECTION_OUTLINE,
492 SP_VERB_SELECTION_UNGROUP,
493 SP_VERB_ZOOM_1_1,
494 SP_VERB_ZOOM_1_2,
495 SP_VERB_ZOOM_2_1,
496 SP_VERB_ZOOM_DRAWING,
497 SP_VERB_ZOOM_IN,
498 SP_VERB_ZOOM_NEXT,
499 SP_VERB_ZOOM_OUT,
500 SP_VERB_ZOOM_PAGE,
501 SP_VERB_ZOOM_PAGE_WIDTH,
502 SP_VERB_ZOOM_PREV,
503 SP_VERB_ZOOM_SELECTION,
504 };
506 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
507 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
509 static std::map<SPDesktop*, GtkActionGroup*> groups;
510 GtkActionGroup* mainActions = 0;
511 if ( groups.find(desktop) != groups.end() ) {
512 mainActions = groups[desktop];
513 }
515 if ( !mainActions ) {
516 mainActions = gtk_action_group_new("main");
517 groups[desktop] = mainActions;
518 }
520 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
521 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
522 if ( verb ) {
523 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
524 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
525 gtk_action_group_add_action( mainActions, act );
526 }
527 }
528 }
530 return mainActions;
531 }
534 GtkWidget *
535 sp_tool_toolbox_new()
536 {
537 GtkTooltips *tt = gtk_tooltips_new();
538 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
540 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
541 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
543 gtk_widget_set_sensitive(tb, FALSE);
545 GtkWidget *hb = gtk_handle_box_new();
546 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
547 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
548 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
550 gtk_container_add(GTK_CONTAINER(hb), tb);
551 gtk_widget_show(GTK_WIDGET(tb));
553 sigc::connection* conn = new sigc::connection;
554 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
556 return hb;
557 }
559 static void
560 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
561 {
562 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
563 gtk_widget_queue_resize(child);
564 }
566 static void
567 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
568 {
569 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
570 gtk_widget_queue_resize(child);
571 }
573 GtkWidget *
574 sp_aux_toolbox_new()
575 {
576 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
578 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
579 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
580 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
581 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
582 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
584 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
585 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
587 gtk_widget_set_sensitive(tb, FALSE);
589 GtkWidget *hb = gtk_handle_box_new();
590 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
591 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
592 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
594 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
595 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
597 gtk_container_add(GTK_CONTAINER(hb), tb);
598 gtk_widget_show(GTK_WIDGET(tb));
600 sigc::connection* conn = new sigc::connection;
601 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
603 return hb;
604 }
606 //####################################
607 //# Commands Bar
608 //####################################
610 GtkWidget *
611 sp_commands_toolbox_new()
612 {
613 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
615 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
616 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
617 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
618 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
619 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
621 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
622 gtk_widget_set_sensitive(tb, FALSE);
624 GtkWidget *hb = gtk_handle_box_new();
625 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
626 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
627 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
629 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
630 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
632 gtk_container_add(GTK_CONTAINER(hb), tb);
633 gtk_widget_show(GTK_WIDGET(tb));
635 sigc::connection* conn = new sigc::connection;
636 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
638 return hb;
639 }
642 //####################################
643 //# node editing callbacks
644 //####################################
646 void
647 sp_node_path_edit_add(void)
648 {
649 sp_node_selected_add_node();
650 }
652 void
653 sp_node_path_edit_delete(void)
654 {
655 sp_node_selected_delete();
656 }
658 void
659 sp_node_path_edit_delete_segment(void)
660 {
661 sp_node_selected_delete_segment();
662 }
664 void
665 sp_node_path_edit_break(void)
666 {
667 sp_node_selected_break();
668 }
670 void
671 sp_node_path_edit_join(void)
672 {
673 sp_node_selected_join();
674 }
676 void
677 sp_node_path_edit_join_segment(void)
678 {
679 sp_node_selected_join_segment();
680 }
682 void
683 sp_node_path_edit_toline(void)
684 {
685 sp_node_selected_set_line_type(NR_LINETO);
686 }
688 void
689 sp_node_path_edit_tocurve(void)
690 {
691 sp_node_selected_set_line_type(NR_CURVETO);
692 }
694 void
695 sp_node_path_edit_cusp(void)
696 {
697 sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
698 }
700 void
701 sp_node_path_edit_smooth(void)
702 {
703 sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
704 }
706 void
707 sp_node_path_edit_symmetrical(void)
708 {
709 sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
710 }
712 static void toggle_show_handles (GtkToggleAction *act, gpointer data) {
713 bool show = gtk_toggle_action_get_active( act );
714 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
715 sp_nodepath_show_handles(show);
716 }
718 //################################
719 //## Node Editing Toolbox ##
720 //################################
722 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
723 {
724 {
725 InkAction* inky = ink_action_new( "NodeInsertAction",
726 _("Insert"),
727 _("Insert new nodes into selected segments"),
728 "node_insert",
729 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
730 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
731 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
732 }
734 {
735 InkAction* inky = ink_action_new( "NodeDeleteAction",
736 _("Delete"),
737 _("Delete selected nodes"),
738 "node_delete",
739 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
740 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
741 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
742 }
744 {
745 InkAction* inky = ink_action_new( "NodeJoinAction",
746 _("Join"),
747 _("Join selected endnodes"),
748 "node_join",
749 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
750 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
751 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
752 }
754 {
755 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
756 _("Join Segment"),
757 _("Join selected endnodes with a new segment"),
758 "node_join_segment",
759 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
760 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
761 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
762 }
764 {
765 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
766 _("Delete Segment"),
767 _("Split path between two non-endpoint nodes"),
768 "node_delete_segment",
769 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
770 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
771 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
772 }
774 {
775 InkAction* inky = ink_action_new( "NodeBreakAction",
776 _("Node Break"),
777 _("Break path at selected nodes"),
778 "node_break",
779 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
780 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
781 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
782 }
784 {
785 InkAction* inky = ink_action_new( "NodeCuspAction",
786 _("Node Cusp"),
787 _("Make selected nodes corner"),
788 "node_cusp",
789 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
790 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
791 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
792 }
794 {
795 InkAction* inky = ink_action_new( "NodeSmoothAction",
796 _("Node Smooth"),
797 _("Make selected nodes smooth"),
798 "node_smooth",
799 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
800 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
801 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
802 }
804 {
805 InkAction* inky = ink_action_new( "NodeSymmetricAction",
806 _("Node Symmetric"),
807 _("Make selected nodes symmetric"),
808 "node_symmetric",
809 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
810 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
811 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
812 }
814 {
815 InkAction* inky = ink_action_new( "NodeLineAction",
816 _("Node Line"),
817 _("Make selected segments lines"),
818 "node_line",
819 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
820 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
821 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
822 }
824 {
825 InkAction* inky = ink_action_new( "NodeCurveAction",
826 _("Node Curve"),
827 _("Make selected segments curves"),
828 "node_curve",
829 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
830 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
831 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
832 }
834 {
835 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
836 _("Show Handles"),
837 _("Show the Bezier handles of selected nodes"),
838 "nodes_show_handles",
839 Inkscape::ICON_SIZE_DECORATION );
840 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
841 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
842 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
843 }
845 } // end of sp_node_toolbox_prep()
848 //########################
849 //## Zoom Toolbox ##
850 //########################
852 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
853 {
854 // no custom GtkAction setup needed
855 } // end of sp_zoom_toolbox_prep()
857 void
858 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
859 {
860 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")));
861 }
864 void
865 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
866 {
867 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")));
868 }
870 void
871 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
872 {
873 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")));
874 }
876 static void
877 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
878 {
879 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
880 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
882 if (old_desktop) {
883 GList *children, *iter;
885 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
886 for ( iter = children ; iter ; iter = iter->next ) {
887 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
888 }
889 g_list_free(children);
890 }
892 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
894 if (desktop) {
895 gtk_widget_set_sensitive(toolbox, TRUE);
896 setup_func(toolbox, desktop);
897 update_func(desktop, desktop->event_context, toolbox);
898 *conn = desktop->connectEventContextChanged
899 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
900 } else {
901 gtk_widget_set_sensitive(toolbox, FALSE);
902 }
904 } // end of toolbox_set_desktop()
907 static void
908 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
909 {
910 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
911 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
912 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
914 for (int i = 0 ; tools[i].type_name ; i++ ) {
915 GtkWidget *button =
916 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
917 SP_BUTTON_TYPE_TOGGLE,
918 Inkscape::Verb::get(tools[i].verb),
919 Inkscape::Verb::get(tools[i].doubleclick_verb),
920 desktop,
921 tooltips );
923 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
924 (gpointer)button );
925 }
926 }
929 static void
930 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
931 {
932 gchar const *const tname = ( eventcontext
933 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
934 : NULL );
935 for (int i = 0 ; tools[i].type_name ; i++ ) {
936 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
937 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
938 }
939 }
941 static void
942 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
943 {
944 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
945 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
946 GtkUIManager* mgr = gtk_ui_manager_new();
947 GError* errVal = 0;
948 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
949 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
951 std::map<std::string, GtkWidget*> dataHolders;
953 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
954 if ( aux_toolboxes[i].prep_func ) {
955 // converted to GtkActions and UIManager
957 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
958 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
959 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
960 dataHolders[aux_toolboxes[i].type_name] = kludge;
961 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
962 } else {
964 GtkWidget *sub_toolbox = 0;
965 if (aux_toolboxes[i].create_func == NULL)
966 sub_toolbox = sp_empty_toolbox_new(desktop);
967 else {
968 sub_toolbox = aux_toolboxes[i].create_func(desktop);
969 }
971 gtk_size_group_add_widget( grouper, sub_toolbox );
973 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
974 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
976 }
977 }
979 // Second pass to create toolbars *after* all GtkActions are created
980 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
981 if ( aux_toolboxes[i].prep_func ) {
982 // converted to GtkActions and UIManager
984 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
986 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
987 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
989 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
990 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
991 g_free( tmp );
992 tmp = 0;
994 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
995 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
996 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
997 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
1000 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
1002 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
1003 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
1004 swatch->setDesktop( desktop );
1005 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
1006 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
1007 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
1008 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 );
1009 }
1011 gtk_widget_show_all( holder );
1012 sp_set_font_size_smaller( holder );
1014 gtk_size_group_add_widget( grouper, holder );
1016 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1017 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1018 }
1019 }
1021 g_object_unref( G_OBJECT(grouper) );
1022 }
1024 static void
1025 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1026 {
1027 gchar const *tname = ( eventcontext
1028 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1029 : NULL );
1030 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1031 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1032 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1033 gtk_widget_show_all(sub_toolbox);
1034 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1035 } else {
1036 gtk_widget_hide(sub_toolbox);
1037 }
1038 }
1039 }
1041 static void
1042 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1043 {
1044 gchar const * descr =
1045 "<ui>"
1046 " <toolbar name='CommandsToolbar'>"
1047 " <toolitem action='FileNew' />"
1048 " <toolitem action='FileOpen' />"
1049 " <toolitem action='FileSave' />"
1050 " <toolitem action='FilePrint' />"
1051 " <separator />"
1052 " <toolitem action='FileImport' />"
1053 " <toolitem action='FileExport' />"
1054 " <separator />"
1055 " <toolitem action='EditUndo' />"
1056 " <toolitem action='EditRedo' />"
1057 " <separator />"
1058 " <toolitem action='EditCopy' />"
1059 " <toolitem action='EditCut' />"
1060 " <toolitem action='EditPaste' />"
1061 " <separator />"
1062 " <toolitem action='ZoomSelection' />"
1063 " <toolitem action='ZoomDrawing' />"
1064 " <toolitem action='ZoomPage' />"
1065 " <separator />"
1066 " <toolitem action='EditDuplicate' />"
1067 " <toolitem action='EditClone' />"
1068 " <toolitem action='EditUnlinkClone' />"
1069 " <separator />"
1070 " <toolitem action='SelectionGroup' />"
1071 " <toolitem action='SelectionUnGroup' />"
1072 " <separator />"
1073 " <toolitem action='DialogFillStroke' />"
1074 " <toolitem action='DialogText' />"
1075 " <toolitem action='DialogXMLEditor' />"
1076 " <toolitem action='DialogAlignDistribute' />"
1077 " <separator />"
1078 " <toolitem action='DialogPreferences' />"
1079 " <toolitem action='DialogDocumentProperties' />"
1080 " </toolbar>"
1081 "</ui>";
1082 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1085 GtkUIManager* mgr = gtk_ui_manager_new();
1086 GError* errVal = 0;
1088 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1089 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1091 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1092 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1093 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1094 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1095 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1098 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1099 }
1101 static void
1102 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1103 {
1104 }
1106 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1107 {
1108 gtk_widget_show(toolbox_toplevel);
1109 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1111 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1112 if (!shown_toolbox) {
1113 return;
1114 }
1115 gtk_widget_show(toolbox);
1117 // need to show the spacer, or the padding will be off
1118 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1119 gtk_widget_show(spacer);
1121 gtk_widget_show_all(shown_toolbox);
1122 }
1124 void
1125 aux_toolbox_space(GtkWidget *tb, gint space)
1126 {
1127 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1128 }
1130 static GtkWidget *
1131 sp_empty_toolbox_new(SPDesktop *desktop)
1132 {
1133 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1134 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1135 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1137 gtk_widget_show_all(tbl);
1138 sp_set_font_size_smaller (tbl);
1140 return tbl;
1141 }
1143 // helper UI functions
1145 GtkWidget *
1146 sp_tb_spinbutton(
1147 gchar *label, gchar const *tooltip,
1148 gchar const *path, gchar const *data, gdouble def,
1149 GtkWidget *us,
1150 GtkWidget *tbl,
1151 gboolean altx, gchar const *altx_mark,
1152 gdouble lower, gdouble upper, gdouble step, gdouble page,
1153 void (*callback)(GtkAdjustment *, GtkWidget *),
1154 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1155 {
1156 GtkTooltips *tt = gtk_tooltips_new();
1158 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1160 GtkWidget *l = gtk_label_new(label);
1161 gtk_widget_show(l);
1162 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1163 gtk_container_add(GTK_CONTAINER(hb), l);
1165 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1166 lower, upper, step, page, page);
1167 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1168 if (us)
1169 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1171 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1172 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1173 if (altx)
1174 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1175 gtk_widget_set_size_request(sb,
1176 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1177 AUX_SPINBUTTON_HEIGHT);
1178 gtk_widget_show(sb);
1179 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1180 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1181 gtk_container_add(GTK_CONTAINER(hb), sb);
1182 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1184 return hb;
1185 }
1187 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
1188 gchar const *label, gchar const *tooltip,
1189 gchar const *path, gchar const *data, gdouble def,
1190 GtkWidget *focusTarget,
1191 GtkWidget *us,
1192 GObject *dataKludge,
1193 gboolean altx, gchar const *altx_mark,
1194 gdouble lower, gdouble upper, gdouble step, gdouble page,
1195 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
1196 void (*callback)(GtkAdjustment *, GObject *),
1197 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
1198 {
1199 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
1200 lower, upper, step, page, page ) );
1201 if (us) {
1202 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
1203 }
1205 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
1207 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
1209 if ( (descrCount > 0) && descrLabels && descrValues ) {
1210 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
1211 }
1213 if ( focusTarget ) {
1214 ege_adjustment_action_set_focuswidget( act, focusTarget );
1215 }
1217 if ( altx && altx_mark ) {
1218 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
1219 }
1221 if ( dataKludge ) {
1222 g_object_set_data( dataKludge, data, adj );
1223 }
1225 // Using a cast just to make sure we pass in the right kind of function pointer
1226 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
1228 return act;
1229 }
1232 #define MODE_LABEL_WIDTH 70
1234 //########################
1235 //## Star ##
1236 //########################
1238 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1239 {
1240 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1242 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1243 // do not remember prefs if this call is initiated by an undo change, because undoing object
1244 // creation sets bogus values to its attributes before it is deleted
1245 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1246 }
1248 // quit if run by the attr_changed listener
1249 if (g_object_get_data( dataKludge, "freeze" )) {
1250 return;
1251 }
1253 // in turn, prevent listener from responding
1254 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1256 bool modmade = false;
1258 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1259 GSList const *items = selection->itemList();
1260 for (; items != NULL; items = items->next) {
1261 if (SP_IS_STAR((SPItem *) items->data)) {
1262 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1263 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1264 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1265 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1266 + M_PI / (gint)adj->value));
1267 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1268 modmade = true;
1269 }
1270 }
1271 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1272 _("Star: Change number of corners"));
1274 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1275 }
1277 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1278 {
1279 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1281 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1282 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1283 }
1285 // quit if run by the attr_changed listener
1286 if (g_object_get_data( dataKludge, "freeze" )) {
1287 return;
1288 }
1290 // in turn, prevent listener from responding
1291 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1293 bool modmade = false;
1294 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1295 GSList const *items = selection->itemList();
1296 for (; items != NULL; items = items->next) {
1297 if (SP_IS_STAR((SPItem *) items->data)) {
1298 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1300 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1301 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1302 if (r2 < r1) {
1303 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1304 } else {
1305 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1306 }
1308 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1309 modmade = true;
1310 }
1311 }
1313 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1314 _("Star: Change spoke ratio"));
1316 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1317 }
1319 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1320 {
1321 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1322 bool flat = ege_select_one_action_get_active( act ) == 0;
1324 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1325 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1326 flat ? "true" : "false" );
1327 }
1329 // quit if run by the attr_changed listener
1330 if (g_object_get_data( dataKludge, "freeze" )) {
1331 return;
1332 }
1334 // in turn, prevent listener from responding
1335 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1337 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1338 GSList const *items = selection->itemList();
1339 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1340 bool modmade = false;
1342 if ( prop_action ) {
1343 gtk_action_set_sensitive( prop_action, !flat );
1344 }
1346 for (; items != NULL; items = items->next) {
1347 if (SP_IS_STAR((SPItem *) items->data)) {
1348 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1349 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1350 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1351 modmade = true;
1352 }
1353 }
1355 if (modmade) {
1356 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1357 flat ? _("Make polygon") : _("Make star"));
1358 }
1360 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1361 }
1363 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1364 {
1365 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1367 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1368 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1369 }
1371 // quit if run by the attr_changed listener
1372 if (g_object_get_data( dataKludge, "freeze" )) {
1373 return;
1374 }
1376 // in turn, prevent listener from responding
1377 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1379 bool modmade = false;
1381 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1382 GSList const *items = selection->itemList();
1383 for (; items != NULL; items = items->next) {
1384 if (SP_IS_STAR((SPItem *) items->data)) {
1385 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1386 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1387 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1388 modmade = true;
1389 }
1390 }
1391 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1392 _("Star: Change rounding"));
1394 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1395 }
1397 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1398 {
1399 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1401 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1402 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1403 }
1405 // quit if run by the attr_changed listener
1406 if (g_object_get_data( dataKludge, "freeze" )) {
1407 return;
1408 }
1410 // in turn, prevent listener from responding
1411 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1413 bool modmade = false;
1415 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1416 GSList const *items = selection->itemList();
1417 for (; items != NULL; items = items->next) {
1418 if (SP_IS_STAR((SPItem *) items->data)) {
1419 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1420 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1421 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1422 modmade = true;
1423 }
1424 }
1425 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1426 _("Star: Change randomization"));
1428 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1429 }
1432 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1433 gchar const *old_value, gchar const *new_value,
1434 bool is_interactive, gpointer data)
1435 {
1436 GtkWidget *tbl = GTK_WIDGET(data);
1438 // quit if run by the _changed callbacks
1439 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1440 return;
1441 }
1443 // in turn, prevent callbacks from responding
1444 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1446 GtkAdjustment *adj = 0;
1448 if (!strcmp(name, "inkscape:randomized")) {
1449 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1450 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1451 } else if (!strcmp(name, "inkscape:rounded")) {
1452 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1453 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1454 } else if (!strcmp(name, "inkscape:flatsided")) {
1455 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1456 char const *flatsides = repr->attribute("inkscape:flatsided");
1457 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1458 if ( flatsides && !strcmp(flatsides,"false") ) {
1459 ege_select_one_action_set_active( flat_action, 1 );
1460 gtk_action_set_sensitive( prop_action, TRUE );
1461 } else {
1462 ege_select_one_action_set_active( flat_action, 0 );
1463 gtk_action_set_sensitive( prop_action, FALSE );
1464 }
1465 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1466 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1467 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1468 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1469 if (r2 < r1) {
1470 gtk_adjustment_set_value(adj, r2/r1);
1471 } else {
1472 gtk_adjustment_set_value(adj, r1/r2);
1473 }
1474 } else if (!strcmp(name, "sodipodi:sides")) {
1475 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1476 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1477 }
1479 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1480 }
1483 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1484 {
1485 NULL, /* child_added */
1486 NULL, /* child_removed */
1487 star_tb_event_attr_changed,
1488 NULL, /* content_changed */
1489 NULL /* order_changed */
1490 };
1493 /**
1494 * \param selection Should not be NULL.
1495 */
1496 static void
1497 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1498 {
1499 int n_selected = 0;
1500 Inkscape::XML::Node *repr = NULL;
1502 purge_repr_listener( tbl, tbl );
1504 for (GSList const *items = selection->itemList();
1505 items != NULL;
1506 items = items->next)
1507 {
1508 if (SP_IS_STAR((SPItem *) items->data)) {
1509 n_selected++;
1510 repr = SP_OBJECT_REPR((SPItem *) items->data);
1511 }
1512 }
1514 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1516 if (n_selected == 0) {
1517 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1518 } else if (n_selected == 1) {
1519 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1521 if (repr) {
1522 g_object_set_data( tbl, "repr", repr );
1523 Inkscape::GC::anchor(repr);
1524 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1525 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1526 }
1527 } else {
1528 // FIXME: implement averaging of all parameters for multiple selected stars
1529 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1530 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1531 }
1532 }
1535 static void sp_stb_defaults( GtkWidget *widget, GObject *dataKludge )
1536 {
1537 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1538 // callbacks to lump all the changes for all selected objects in one undo step
1540 GtkAdjustment *adj = 0;
1542 // fixme: make settable in prefs!
1543 gint mag = 5;
1544 gdouble prop = 0.5;
1545 gboolean flat = FALSE;
1546 gdouble randomized = 0;
1547 gdouble rounded = 0;
1549 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1550 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1552 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1553 gtk_action_set_sensitive( sb2, !flat );
1555 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1556 gtk_adjustment_set_value(adj, mag);
1557 gtk_adjustment_value_changed(adj);
1559 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1560 gtk_adjustment_set_value(adj, prop);
1561 gtk_adjustment_value_changed(adj);
1563 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1564 gtk_adjustment_set_value(adj, rounded);
1565 gtk_adjustment_value_changed(adj);
1567 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1568 gtk_adjustment_set_value(adj, randomized);
1569 gtk_adjustment_value_changed(adj);
1570 }
1573 void
1574 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1575 {
1576 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1577 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1578 GtkWidget *l = gtk_label_new(NULL);
1579 gtk_label_set_markup(GTK_LABEL(l), title);
1580 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1581 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1582 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1583 }
1586 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1587 {
1588 {
1589 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1590 ege_output_action_set_use_markup( act, TRUE );
1591 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1592 g_object_set_data( holder, "mode_action", act );
1593 }
1595 {
1596 //EgeAdjustmentAction* calligraphy_angle = 0;
1597 EgeAdjustmentAction* eact = 0;
1598 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1599 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1601 /* Flatsided checkbox */
1602 {
1603 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1605 GtkTreeIter iter;
1606 gtk_list_store_append( model, &iter );
1607 gtk_list_store_set( model, &iter,
1608 0, _("Polygon"),
1609 1, _("Regular polygon (with one handle) instead of a star"),
1610 2, "star_flat",
1611 -1 );
1613 gtk_list_store_append( model, &iter );
1614 gtk_list_store_set( model, &iter,
1615 0, _("Star"),
1616 1, _("Star instead of a regular polygon (with one handle)"),
1617 2, "star_angled",
1618 -1 );
1620 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
1621 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1622 g_object_set_data( holder, "flat_action", act );
1624 ege_select_one_action_set_appearance( act, "full" );
1625 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1626 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1627 ege_select_one_action_set_icon_column( act, 2 );
1628 ege_select_one_action_set_tooltip_column( act, 1 );
1630 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1631 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1632 }
1634 /* Magnitude */
1635 //gchar const* labels[] = {_("tri (default)"), _("quad"), _("pent")};
1636 //gdouble values[] = {3, 4, 5};
1637 eact = create_adjustment_action( "MagnitudeAction",
1638 _("Corners:"), _("Number of corners of a polygon or star"),
1639 "tools.shapes.star", "magnitude", 3,
1640 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1641 3, 1024, 1, 5,
1642 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
1643 sp_stb_magnitude_value_changed,
1644 1.0, 0 );
1645 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1646 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1648 /* Spoke ratio */
1649 //gchar const* labels2[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1650 //gdouble values2[] = {-90, 0, 30, 90};
1651 eact = create_adjustment_action( "SpokeAction",
1652 _("Spoke ratio:"),
1653 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1654 // Base radius is the same for the closest handle.
1655 _("Base radius to tip radius ratio"),
1656 "tools.shapes.star", "proportion", 0.5,
1657 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1658 0.01, 1.0, 0.01, 0.1,
1659 0, 0, 0, // labels2, values2, G_N_ELEMENTS(labels2),
1660 sp_stb_proportion_value_changed );
1661 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1662 g_object_set_data( holder, "prop_action", eact );
1664 if ( !isFlatSided ) {
1665 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1666 } else {
1667 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1668 }
1670 /* Roundedness */
1671 //gchar const* labels3[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1672 //gdouble values3[] = {-90, 0, 30, 90};
1673 eact = create_adjustment_action( "RoundednessAction",
1674 _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1675 "tools.shapes.star", "rounded", 0.0,
1676 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1677 -100.0, 100.0, 0.01, 0.1,
1678 0, 0, 0, // labels3, values3, G_N_ELEMENTS(labels3),
1679 sp_stb_rounded_value_changed );
1680 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1681 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1683 /* Randomization */
1684 //gchar const* labels4[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1685 //gdouble values4[] = {-90, 0, 30, 90};
1686 eact = create_adjustment_action( "RandomizationAction",
1687 _("Randomized:"), _("Scatter randomly the corners and angles"),
1688 "tools.shapes.star", "randomized", 0.0,
1689 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1690 -10.0, 10.0, 0.001, 0.01,
1691 0, 0, 0, // labels4, values4, G_N_ELEMENTS(labels4),
1692 sp_stb_randomized_value_changed, 0.1, 3 );
1693 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1694 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1695 }
1697 {
1698 /* Reset */
1699 {
1700 GtkAction* act = gtk_action_new( "StarResetAction",
1701 _("Defaults"),
1702 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1703 GTK_STOCK_CLEAR );
1704 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1705 gtk_action_group_add_action( mainActions, act );
1706 gtk_action_set_sensitive( act, TRUE );
1707 }
1708 }
1710 sigc::connection *connection = new sigc::connection(
1711 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1712 );
1713 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1714 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
1715 }
1718 //########################
1719 //## Rect ##
1720 //########################
1722 static void sp_rtb_sensitivize( GObject *tbl )
1723 {
1724 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
1725 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
1726 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
1728 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
1729 gtk_action_set_sensitive( not_rounded, FALSE );
1730 } else {
1731 gtk_action_set_sensitive( not_rounded, TRUE );
1732 }
1733 }
1736 static void
1737 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
1738 void (*setter)(SPRect *, gdouble))
1739 {
1740 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1742 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1743 SPUnit const *unit = tracker->getActiveUnit();
1745 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1746 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1747 }
1749 // quit if run by the attr_changed listener
1750 if (g_object_get_data( tbl, "freeze" )) {
1751 return;
1752 }
1754 // in turn, prevent listener from responding
1755 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1757 bool modmade = false;
1758 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1759 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1760 if (SP_IS_RECT(items->data)) {
1761 if (adj->value != 0) {
1762 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1763 } else {
1764 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1765 }
1766 modmade = true;
1767 }
1768 }
1770 sp_rtb_sensitivize( tbl );
1772 if (modmade) {
1773 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
1774 _("Change rectangle"));
1775 }
1777 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1778 }
1780 static void
1781 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
1782 {
1783 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1784 }
1786 static void
1787 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
1788 {
1789 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1790 }
1792 static void
1793 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
1794 {
1795 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1796 }
1798 static void
1799 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
1800 {
1801 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1802 }
1806 static void
1807 sp_rtb_defaults( GtkWidget *widget, GObject *obj)
1808 {
1809 GtkAdjustment *adj = 0;
1811 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
1812 gtk_adjustment_set_value(adj, 0.0);
1813 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1814 gtk_adjustment_value_changed(adj);
1816 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
1817 gtk_adjustment_set_value(adj, 0.0);
1818 gtk_adjustment_value_changed(adj);
1820 sp_rtb_sensitivize( obj );
1821 }
1823 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1824 gchar const *old_value, gchar const *new_value,
1825 bool is_interactive, gpointer data)
1826 {
1827 GObject *tbl = G_OBJECT(data);
1829 // quit if run by the _changed callbacks
1830 if (g_object_get_data( tbl, "freeze" )) {
1831 return;
1832 }
1834 // in turn, prevent callbacks from responding
1835 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
1837 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1838 SPUnit const *unit = tracker->getActiveUnit();
1840 gpointer item = g_object_get_data( tbl, "item" );
1841 if (item && SP_IS_RECT(item)) {
1842 {
1843 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
1844 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1845 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1846 }
1848 {
1849 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
1850 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1851 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1852 }
1854 {
1855 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
1856 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1857 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1858 }
1860 {
1861 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
1862 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1863 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1864 }
1865 }
1867 sp_rtb_sensitivize( tbl );
1869 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1870 }
1873 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1874 NULL, /* child_added */
1875 NULL, /* child_removed */
1876 rect_tb_event_attr_changed,
1877 NULL, /* content_changed */
1878 NULL /* order_changed */
1879 };
1881 /**
1882 * \param selection should not be NULL.
1883 */
1884 static void
1885 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1886 {
1887 int n_selected = 0;
1888 Inkscape::XML::Node *repr = NULL;
1889 SPItem *item = NULL;
1891 if ( g_object_get_data( tbl, "repr" ) ) {
1892 g_object_set_data( tbl, "item", NULL );
1893 }
1894 purge_repr_listener( tbl, tbl );
1896 for (GSList const *items = selection->itemList();
1897 items != NULL;
1898 items = items->next) {
1899 if (SP_IS_RECT((SPItem *) items->data)) {
1900 n_selected++;
1901 item = (SPItem *) items->data;
1902 repr = SP_OBJECT_REPR(item);
1903 }
1904 }
1906 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1908 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
1910 if (n_selected == 0) {
1911 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1913 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1914 gtk_action_set_sensitive(w, FALSE);
1915 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1916 gtk_action_set_sensitive(h, FALSE);
1918 } else if (n_selected == 1) {
1919 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1920 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
1922 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1923 gtk_action_set_sensitive(w, TRUE);
1924 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1925 gtk_action_set_sensitive(h, TRUE);
1927 if (repr) {
1928 g_object_set_data( tbl, "repr", repr );
1929 g_object_set_data( tbl, "item", item );
1930 Inkscape::GC::anchor(repr);
1931 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1932 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1933 }
1934 } else {
1935 // FIXME: implement averaging of all parameters for multiple selected
1936 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1937 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1938 sp_rtb_sensitivize( tbl );
1939 }
1940 }
1943 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1944 {
1945 EgeAdjustmentAction* eact = 0;
1947 {
1948 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
1949 ege_output_action_set_use_markup( act, TRUE );
1950 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1951 g_object_set_data( holder, "mode_action", act );
1952 }
1954 // rx/ry units menu: create
1955 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1956 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
1957 // fixme: add % meaning per cent of the width/height
1958 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1959 g_object_set_data( holder, "tracker", tracker );
1961 /* W */
1962 {
1963 eact = create_adjustment_action( "RectWidthAction",
1964 _("W:"), _("Width of rectangle"),
1965 "tools.shapes.rect", "width", 0,
1966 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
1967 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1968 0, 0, 0,
1969 sp_rtb_width_value_changed );
1970 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1971 g_object_set_data( holder, "width_action", eact );
1972 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1973 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1974 }
1976 /* H */
1977 {
1978 eact = create_adjustment_action( "RectHeightAction",
1979 _("H:"), _("Height of rectangle"),
1980 "tools.shapes.rect", "height", 0,
1981 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1982 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1983 0, 0, 0,
1984 sp_rtb_height_value_changed );
1985 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1986 g_object_set_data( holder, "height_action", eact );
1987 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1988 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1989 }
1991 /* rx */
1992 {
1993 eact = create_adjustment_action( "RadiusXAction",
1994 _("Rx:"), _("Horizontal radius of rounded corners"),
1995 "tools.shapes.rect", "rx", 0,
1996 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1997 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1998 0, 0, 0,
1999 sp_rtb_rx_value_changed);
2000 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2001 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2002 }
2004 /* ry */
2005 {
2006 eact = create_adjustment_action( "RadiusYAction",
2007 _("Ry:"), _("Vertical radius of rounded corners"),
2008 "tools.shapes.rect", "ry", 0,
2009 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2010 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2011 0, 0, 0,
2012 sp_rtb_ry_value_changed);
2013 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2014 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2015 }
2017 // add the units menu
2018 {
2019 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), _("") );
2020 gtk_action_group_add_action( mainActions, act );
2021 }
2023 /* Reset */
2024 {
2025 InkAction* inky = ink_action_new( "RectResetAction",
2026 _("Not rounded"),
2027 _("Make corners sharp"),
2028 "squared_corner",
2029 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2030 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2031 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2032 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2033 g_object_set_data( holder, "not_rounded", inky );
2034 }
2036 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2037 sp_rtb_sensitivize( holder );
2039 sigc::connection *connection = new sigc::connection(
2040 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2041 );
2042 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2043 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2044 }
2046 //########################
2047 //## Spiral ##
2048 //########################
2050 static void
2051 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2052 {
2053 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2055 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2056 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2057 }
2059 // quit if run by the attr_changed listener
2060 if (g_object_get_data( tbl, "freeze" )) {
2061 return;
2062 }
2064 // in turn, prevent listener from responding
2065 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2067 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2069 bool modmade = false;
2070 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2071 items != NULL;
2072 items = items->next)
2073 {
2074 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2075 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2076 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2077 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2078 modmade = true;
2079 }
2080 }
2082 g_free(namespaced_name);
2084 if (modmade) {
2085 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2086 _("Change spiral"));
2087 }
2089 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2090 }
2092 static void
2093 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2094 {
2095 sp_spl_tb_value_changed(adj, tbl, "revolution");
2096 }
2098 static void
2099 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2100 {
2101 sp_spl_tb_value_changed(adj, tbl, "expansion");
2102 }
2104 static void
2105 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2106 {
2107 sp_spl_tb_value_changed(adj, tbl, "t0");
2108 }
2110 static void
2111 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
2112 {
2113 GtkWidget *tbl = GTK_WIDGET(obj);
2115 GtkAdjustment *adj;
2117 // fixme: make settable
2118 gdouble rev = 5;
2119 gdouble exp = 1.0;
2120 gdouble t0 = 0.0;
2122 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2123 gtk_adjustment_set_value(adj, rev);
2124 gtk_adjustment_value_changed(adj);
2126 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2127 gtk_adjustment_set_value(adj, exp);
2128 gtk_adjustment_value_changed(adj);
2130 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2131 gtk_adjustment_set_value(adj, t0);
2132 gtk_adjustment_value_changed(adj);
2134 spinbutton_defocus(GTK_OBJECT(tbl));
2135 }
2138 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2139 gchar const *old_value, gchar const *new_value,
2140 bool is_interactive, gpointer data)
2141 {
2142 GtkWidget *tbl = GTK_WIDGET(data);
2144 // quit if run by the _changed callbacks
2145 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2146 return;
2147 }
2149 // in turn, prevent callbacks from responding
2150 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2152 GtkAdjustment *adj;
2153 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2154 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2156 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2157 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2159 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2160 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2162 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2163 }
2166 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2167 NULL, /* child_added */
2168 NULL, /* child_removed */
2169 spiral_tb_event_attr_changed,
2170 NULL, /* content_changed */
2171 NULL /* order_changed */
2172 };
2174 static void
2175 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2176 {
2177 int n_selected = 0;
2178 Inkscape::XML::Node *repr = NULL;
2180 purge_repr_listener( tbl, tbl );
2182 for (GSList const *items = selection->itemList();
2183 items != NULL;
2184 items = items->next)
2185 {
2186 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2187 n_selected++;
2188 repr = SP_OBJECT_REPR((SPItem *) items->data);
2189 }
2190 }
2192 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2194 if (n_selected == 0) {
2195 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2196 } else if (n_selected == 1) {
2197 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2199 if (repr) {
2200 g_object_set_data( tbl, "repr", repr );
2201 Inkscape::GC::anchor(repr);
2202 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2203 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2204 }
2205 } else {
2206 // FIXME: implement averaging of all parameters for multiple selected
2207 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2208 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2209 }
2210 }
2213 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2214 {
2215 EgeAdjustmentAction* eact = 0;
2217 {
2218 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2219 ege_output_action_set_use_markup( act, TRUE );
2220 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2221 g_object_set_data( holder, "mode_action", act );
2222 }
2224 /* Revolution */
2225 {
2226 eact = create_adjustment_action( "SpiralRevolutionAction",
2227 _("Turns:"), _("Number of revolutions"),
2228 "tools.shapes.spiral", "revolution", 3.0,
2229 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2230 0.01, 1024.0, 0.1, 1.0,
2231 0, 0, 0,
2232 sp_spl_tb_revolution_value_changed, 1, 2);
2233 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2234 }
2236 /* Expansion */
2237 {
2238 eact = create_adjustment_action( "SpiralExpansionAction",
2239 _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2240 "tools.shapes.spiral", "expansion", 1.0,
2241 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2242 0.0, 1000.0, 0.01, 1.0,
2243 0, 0, 0,
2244 sp_spl_tb_expansion_value_changed);
2245 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2246 }
2248 /* T0 */
2249 {
2250 eact = create_adjustment_action( "SpiralT0Action",
2251 _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2252 "tools.shapes.spiral", "t0", 0.0,
2253 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2254 0.0, 0.999, 0.01, 1.0,
2255 0, 0, 0,
2256 sp_spl_tb_t0_value_changed);
2257 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2258 }
2260 /* Reset */
2261 {
2262 InkAction* inky = ink_action_new( "SpiralResetAction",
2263 _("Defaults"),
2264 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2265 GTK_STOCK_CLEAR,
2266 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2267 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2268 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2269 }
2272 sigc::connection *connection = new sigc::connection(
2273 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2274 );
2275 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2276 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2277 }
2279 //########################
2280 //## Pen/Pencil ##
2281 //########################
2284 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2285 {
2286 // Put stuff here
2287 }
2289 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2290 {
2291 // Put stuff here
2292 }
2295 //########################
2296 //## Calligraphy ##
2297 //########################
2299 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
2300 {
2301 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
2302 }
2304 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
2305 {
2306 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
2307 }
2309 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
2310 {
2311 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
2312 }
2314 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
2315 {
2316 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
2317 }
2319 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
2320 {
2321 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
2322 }
2324 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
2325 {
2326 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
2327 }
2329 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
2330 {
2331 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
2332 }
2334 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
2335 {
2336 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
2337 }
2339 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer data )
2340 {
2341 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2342 }
2344 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer data )
2345 {
2346 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
2347 }
2349 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
2350 {
2351 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2353 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
2354 }
2356 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
2357 {
2358 // FIXME: make defaults settable via Inkscape Options
2359 struct KeyValue {
2360 char const *key;
2361 double value;
2362 } const key_values[] = {
2363 {"mass", 0.02},
2364 {"wiggle", 0.0},
2365 {"angle", 30.0},
2366 {"width", 15},
2367 {"thinning", 0.1},
2368 {"tremor", 0.0},
2369 {"flatness", 0.9},
2370 {"cap_rounding", 0.0}
2371 };
2373 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2374 KeyValue const &kv = key_values[i];
2375 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
2376 if ( adj ) {
2377 gtk_adjustment_set_value(adj, kv.value);
2378 }
2379 }
2380 }
2383 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2384 {
2385 {
2386 EgeAdjustmentAction* calligraphy_angle = 0;
2388 {
2389 /* Width */
2390 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
2391 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2392 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
2393 _("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2394 "tools.calligraphic", "width", 15,
2395 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
2396 1, 100, 1.0, 10.0,
2397 labels, values, G_N_ELEMENTS(labels),
2398 sp_ddc_width_value_changed, 0.01, 0, 100 );
2399 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2400 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2401 }
2403 {
2404 /* Thinning */
2405 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
2406 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
2407 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
2408 _("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2409 "tools.calligraphic", "thinning", 0.1,
2410 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2411 -1.0, 1.0, 0.01, 0.1,
2412 labels, values, G_N_ELEMENTS(labels),
2413 sp_ddc_velthin_value_changed, 0.01, 2);
2414 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2415 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2416 }
2418 {
2419 /* Angle */
2420 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
2421 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2422 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
2423 _("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2424 "tools.calligraphic", "angle", 30,
2425 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
2426 -90.0, 90.0, 1.0, 10.0,
2427 labels, values, G_N_ELEMENTS(labels),
2428 sp_ddc_angle_value_changed, 1, 0 );
2429 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2430 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2431 calligraphy_angle = eact;
2432 }
2434 {
2435 /* Fixation */
2436 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
2437 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
2438 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
2439 _("Fixation:"), _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
2440 "tools.calligraphic", "flatness", 0.9,
2441 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2442 0.0, 1.0, 0.01, 0.1,
2443 labels, values, G_N_ELEMENTS(labels),
2444 sp_ddc_flatness_value_changed, 0.01, 2 );
2445 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2446 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2447 }
2449 {
2450 /* Cap Rounding */
2451 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
2452 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
2453 // TRANSLATORS: "cap" means "end" (both start and finish) here
2454 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
2455 _("Caps:"), _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
2456 "tools.calligraphic", "cap_rounding", 0.0,
2457 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2458 0.0, 5.0, 0.01, 0.1,
2459 labels, values, G_N_ELEMENTS(labels),
2460 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
2461 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2462 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2463 }
2465 {
2466 /* Tremor */
2467 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
2468 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
2469 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
2470 _("Tremor:"), _("Increase to make strokes rugged and trembling"),
2471 "tools.calligraphic", "tremor", 0.0,
2472 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2473 0.0, 1.0, 0.01, 0.1,
2474 labels, values, G_N_ELEMENTS(labels),
2475 sp_ddc_tremor_value_changed, 0.01, 2 );
2477 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2478 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2479 }
2481 {
2482 /* Wiggle */
2483 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
2484 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
2485 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
2486 _("Wiggle:"), _("Increase to make the pen waver and wiggle"),
2487 "tools.calligraphic", "wiggle", 0.0,
2488 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2489 0.0, 1.0, 0.01, 0.1,
2490 labels, values, G_N_ELEMENTS(labels),
2491 sp_ddc_wiggle_value_changed, 0.01, 2 );
2492 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2493 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2494 }
2496 {
2497 /* Mass */
2498 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
2499 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
2500 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
2501 _("Mass:"), _("Increase to make the pen drag behind, as if slowed by inertia"),
2502 "tools.calligraphic", "mass", 0.02,
2503 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2504 0.0, 1.0, 0.01, 0.1,
2505 labels, values, G_N_ELEMENTS(labels),
2506 sp_ddc_mass_value_changed, 0.01, 2 );
2507 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2508 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2509 }
2512 /* Trace Background button */
2513 {
2514 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
2515 _("Trace Background"),
2516 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
2517 "trace_background",
2518 Inkscape::ICON_SIZE_DECORATION );
2519 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2520 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
2521 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
2522 }
2524 /* Use Pressure button */
2525 {
2526 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
2527 _("Pressure"),
2528 _("Use the pressure of the input device to alter the width of the pen"),
2529 "use_pressure",
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_pressure_state_changed), NULL);
2533 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
2534 }
2536 /* Use Tilt button */
2537 {
2538 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
2539 _("Tilt"),
2540 _("Use the tilt of the input device to alter the angle of the pen's nib"),
2541 "use_tilt",
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_tilt_state_changed), calligraphy_angle );
2545 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2546 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2547 }
2549 /* Reset */
2550 {
2551 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
2552 _("Defaults"),
2553 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2554 GTK_STOCK_CLEAR );
2555 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
2556 gtk_action_group_add_action( mainActions, act );
2557 gtk_action_set_sensitive( act, TRUE );
2558 }
2559 }
2560 }
2563 //########################
2564 //## Circle / Arc ##
2565 //########################
2567 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
2568 {
2569 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
2570 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
2572 if (v1 == 0 && v2 == 0) {
2573 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
2574 gtk_action_set_sensitive( ocb, FALSE );
2575 gtk_action_set_sensitive( make_whole, FALSE );
2576 }
2577 } else {
2578 gtk_action_set_sensitive( ocb, TRUE );
2579 gtk_action_set_sensitive( make_whole, TRUE );
2580 }
2581 }
2583 static void
2584 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
2585 {
2586 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2588 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2589 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2590 }
2592 // quit if run by the attr_changed listener
2593 if (g_object_get_data( tbl, "freeze" )) {
2594 return;
2595 }
2597 // in turn, prevent listener from responding
2598 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2600 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2602 bool modmade = false;
2603 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2604 items != NULL;
2605 items = items->next)
2606 {
2607 SPItem *item = SP_ITEM(items->data);
2609 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2611 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2612 SPArc *arc = SP_ARC(item);
2614 if (!strcmp(value_name, "start"))
2615 ge->start = (adj->value * M_PI)/ 180;
2616 else
2617 ge->end = (adj->value * M_PI)/ 180;
2619 sp_genericellipse_normalize(ge);
2620 ((SPObject *)arc)->updateRepr();
2621 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2623 modmade = true;
2624 }
2625 }
2627 g_free(namespaced_name);
2629 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
2631 sp_arctb_sensitivize( tbl, adj->value, other->value );
2633 if (modmade) {
2634 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
2635 _("Arc: Change start/end"));
2636 }
2638 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2639 }
2642 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
2643 {
2644 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
2645 }
2647 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
2648 {
2649 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
2650 }
2652 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
2653 {
2654 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2655 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2656 if ( ege_select_one_action_get_active( act ) != 0 ) {
2657 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2658 } else {
2659 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2660 }
2661 }
2663 // quit if run by the attr_changed listener
2664 if (g_object_get_data( tbl, "freeze" )) {
2665 return;
2666 }
2668 // in turn, prevent listener from responding
2669 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2671 bool modmade = false;
2673 if ( ege_select_one_action_get_active(act) != 0 ) {
2674 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2675 items != NULL;
2676 items = items->next)
2677 {
2678 if (SP_IS_ARC((SPItem *) items->data)) {
2679 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2680 repr->setAttribute("sodipodi:open", "true");
2681 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2682 modmade = true;
2683 }
2684 }
2685 } else {
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", NULL);
2693 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2694 modmade = true;
2695 }
2696 }
2697 }
2699 if (modmade) {
2700 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
2701 _("Arc: Change open/closed"));
2702 }
2704 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2705 }
2707 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
2708 {
2709 GtkAdjustment *adj;
2710 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
2711 gtk_adjustment_set_value(adj, 0.0);
2712 gtk_adjustment_value_changed(adj);
2714 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
2715 gtk_adjustment_set_value(adj, 0.0);
2716 gtk_adjustment_value_changed(adj);
2718 spinbutton_defocus( GTK_OBJECT(obj) );
2719 }
2721 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2722 gchar const *old_value, gchar const *new_value,
2723 bool is_interactive, gpointer data)
2724 {
2725 GObject *tbl = G_OBJECT(data);
2727 // quit if run by the _changed callbacks
2728 if (g_object_get_data( tbl, "freeze" )) {
2729 return;
2730 }
2732 // in turn, prevent callbacks from responding
2733 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2735 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2736 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2738 GtkAdjustment *adj1,*adj2;
2739 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
2740 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2741 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
2742 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2744 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
2746 char const *openstr = NULL;
2747 openstr = repr->attribute("sodipodi:open");
2748 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
2750 if (openstr) {
2751 ege_select_one_action_set_active( ocb, 1 );
2752 } else {
2753 ege_select_one_action_set_active( ocb, 0 );
2754 }
2756 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2757 }
2759 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2760 NULL, /* child_added */
2761 NULL, /* child_removed */
2762 arc_tb_event_attr_changed,
2763 NULL, /* content_changed */
2764 NULL /* order_changed */
2765 };
2768 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2769 {
2770 int n_selected = 0;
2771 Inkscape::XML::Node *repr = NULL;
2773 purge_repr_listener( tbl, tbl );
2775 for (GSList const *items = selection->itemList();
2776 items != NULL;
2777 items = items->next)
2778 {
2779 if (SP_IS_ARC((SPItem *) items->data)) {
2780 n_selected++;
2781 repr = SP_OBJECT_REPR((SPItem *) items->data);
2782 }
2783 }
2785 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2787 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2788 if (n_selected == 0) {
2789 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2790 } else if (n_selected == 1) {
2791 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2792 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2794 if (repr) {
2795 g_object_set_data( tbl, "repr", repr );
2796 Inkscape::GC::anchor(repr);
2797 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2798 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2799 }
2800 } else {
2801 // FIXME: implement averaging of all parameters for multiple selected
2802 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2803 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2804 sp_arctb_sensitivize( tbl, 1, 0 );
2805 }
2806 }
2809 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2810 {
2811 EgeAdjustmentAction* eact = 0;
2814 {
2815 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
2816 ege_output_action_set_use_markup( act, TRUE );
2817 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2818 g_object_set_data( holder, "mode_action", act );
2819 }
2821 /* Start */
2822 {
2823 eact = create_adjustment_action( "ArcStartAction",
2824 _("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2825 "tools.shapes.arc", "start", 0.0,
2826 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
2827 -360.0, 360.0, 1.0, 10.0,
2828 0, 0, 0,
2829 sp_arctb_start_value_changed);
2830 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2831 }
2833 /* End */
2834 {
2835 eact = create_adjustment_action( "ArcEndAction",
2836 _("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2837 "tools.shapes.arc", "end", 0.0,
2838 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2839 -360.0, 360.0, 1.0, 10.0,
2840 0, 0, 0,
2841 sp_arctb_end_value_changed);
2842 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2843 }
2845 /* Segments / Pie checkbox */
2846 {
2847 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2849 GtkTreeIter iter;
2850 gtk_list_store_append( model, &iter );
2851 gtk_list_store_set( model, &iter,
2852 0, _("Closed arc"),
2853 1, _("Switch to segment (closed shape with two radii)"),
2854 2, "circle_closed_arc",
2855 -1 );
2857 gtk_list_store_append( model, &iter );
2858 gtk_list_store_set( model, &iter,
2859 0, _("Open Arc"),
2860 1, _("Switch to arc (unclosed shape)"),
2861 2, "circle_open_arc",
2862 -1 );
2864 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
2865 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2866 g_object_set_data( holder, "open_action", act );
2868 ege_select_one_action_set_appearance( act, "full" );
2869 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2870 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2871 ege_select_one_action_set_icon_column( act, 2 );
2872 ege_select_one_action_set_tooltip_column( act, 1 );
2874 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2875 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
2876 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
2877 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
2878 }
2880 /* Make Whole */
2881 {
2882 InkAction* inky = ink_action_new( "ArcResetAction",
2883 _("Make whole"),
2884 _("Make the shape a whole ellipse, not arc or segment"),
2885 "reset_circle",
2886 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2887 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
2888 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2889 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2890 g_object_set_data( holder, "make_whole", inky );
2891 }
2893 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
2894 // sensitivize make whole and open checkbox
2895 {
2896 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
2897 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
2898 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
2899 }
2902 sigc::connection *connection = new sigc::connection(
2903 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
2904 );
2905 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2906 g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
2907 }
2912 // toggle button callbacks and updaters
2914 //########################
2915 //## Dropper ##
2916 //########################
2918 static void toggle_dropper_pick_alpha( GtkToggleAction* act, gpointer tbl ) {
2919 prefs_set_int_attribute( "tools.dropper", "pick", gtk_toggle_action_get_active( act ) );
2920 GtkAction* set_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "set_action") );
2921 if ( set_action ) {
2922 if ( gtk_toggle_action_get_active( act ) ) {
2923 gtk_action_set_sensitive( set_action, TRUE );
2924 } else {
2925 gtk_action_set_sensitive( set_action, FALSE );
2926 }
2927 }
2929 spinbutton_defocus(GTK_OBJECT(tbl));
2930 }
2932 static void toggle_dropper_set_alpha( GtkToggleAction* act, gpointer tbl ) {
2933 prefs_set_int_attribute( "tools.dropper", "setalpha", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2934 spinbutton_defocus(GTK_OBJECT(tbl));
2935 }
2938 /**
2939 * Dropper auxiliary toolbar construction and setup.
2940 *
2941 * TODO: Would like to add swatch of current color.
2942 * TODO: Add queue of last 5 or so colors selected with new swatches so that
2943 * can drag and drop places. Will provide a nice mixing palette.
2944 */
2945 static void sp_dropper_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2946 {
2947 gint pickAlpha = prefs_get_int_attribute( "tools.dropper", "pick", 1 );
2949 {
2950 InkToggleAction* act = ink_toggle_action_new( "DropperPickAlphaAction",
2951 _("Pick alpha"),
2952 _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"),
2953 "color_alpha_get",
2954 Inkscape::ICON_SIZE_DECORATION );
2955 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2956 g_object_set_data( holder, "pick_action", act );
2957 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), pickAlpha );
2958 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_pick_alpha), holder );
2959 }
2961 {
2962 InkToggleAction* act = ink_toggle_action_new( "DropperSetAlphaAction",
2963 _("Set alpha"),
2964 _("If alpha was picked, assign it to selection as fill or stroke transparency"),
2965 "color_alpha_set",
2966 Inkscape::ICON_SIZE_DECORATION );
2967 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2968 g_object_set_data( holder, "set_action", act );
2969 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.dropper", "setalpha", 1 ) );
2970 // make sure it's disabled if we're not picking alpha
2971 gtk_action_set_sensitive( GTK_ACTION(act), pickAlpha );
2972 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_dropper_set_alpha), holder );
2973 }
2974 }
2977 //########################
2978 //## Text Toolbox ##
2979 //########################
2980 /*
2981 static void
2982 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
2983 {
2984 //Call back for letter sizing spinbutton
2985 }
2987 static void
2988 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
2989 {
2990 //Call back for line height spinbutton
2991 }
2993 static void
2994 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
2995 {
2996 //Call back for horizontal kerning spinbutton
2997 }
2999 static void
3000 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3001 {
3002 //Call back for vertical kerning spinbutton
3003 }
3005 static void
3006 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3007 {
3008 //Call back for letter rotation spinbutton
3009 }*/
3011 namespace {
3013 bool visible = false;
3015 void
3016 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
3017 {
3019 SPStyle *query =
3020 sp_style_new ();
3022 int result_family =
3023 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3025 int result_style =
3026 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3028 int result_numbers =
3029 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3031 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3033 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3034 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3035 {
3036 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3038 if (repr)
3039 {
3040 sp_style_read_from_repr (query, repr);
3041 }
3042 else
3043 {
3044 return;
3045 }
3046 }
3048 if (query->text)
3049 {
3050 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3051 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3052 gtk_entry_set_text (GTK_ENTRY (entry), "");
3054 } else if (query->text->font_family.value) {
3056 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3057 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3059 Gtk::TreePath path;
3060 try {
3061 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3062 } catch (...) {
3063 return;
3064 }
3066 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3067 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3069 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3071 gtk_tree_selection_select_path (tselection, path.gobj());
3072 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3074 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3075 }
3077 //Size
3078 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3079 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3080 g_object_set_data (tbl, "size-block", gpointer(1));
3081 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3082 g_object_set_data (tbl, "size-block", gpointer(0));
3083 free (str);
3085 //Anchor
3086 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3087 {
3088 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3089 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3090 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3091 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3092 }
3093 else
3094 {
3095 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3096 {
3097 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3098 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3099 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3100 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3101 }
3102 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3103 {
3104 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3105 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3106 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3107 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3108 }
3109 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3110 {
3111 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3112 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3113 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3114 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3115 }
3116 }
3118 //Style
3119 {
3120 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3122 gboolean active = gtk_toggle_button_get_active (button);
3123 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3125 if (active != check)
3126 {
3127 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3128 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3129 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3130 }
3131 }
3133 {
3134 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3136 gboolean active = gtk_toggle_button_get_active (button);
3137 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3139 if (active != check)
3140 {
3141 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3142 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3143 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3144 }
3145 }
3147 //Orientation
3148 //locking both buttons, changing one affect all group (both)
3149 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3150 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3152 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3153 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3155 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3156 {
3157 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3158 }
3159 else
3160 {
3161 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3162 }
3163 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3164 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3165 }
3166 }
3168 void
3169 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
3170 {
3171 sp_text_toolbox_selection_changed (selection, tbl);
3172 }
3174 void
3175 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3176 {
3177 sp_text_toolbox_selection_changed (NULL, tbl);
3178 }
3180 void
3181 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
3182 GObject *tbl)
3183 {
3184 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3185 GtkTreeModel *model = 0;
3186 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3187 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3188 GtkTreeIter iter;
3189 char *family = 0;
3191 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3192 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3194 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3195 return;
3196 }
3198 gtk_tree_model_get (model, &iter, 0, &family, -1);
3200 if (g_object_get_data (G_OBJECT (selection), "block"))
3201 {
3202 gtk_entry_set_text (GTK_ENTRY (entry), family);
3203 return;
3204 }
3206 gtk_widget_hide (popdown);
3207 visible = false;
3209 gtk_entry_set_text (GTK_ENTRY (entry), family);
3211 SPStyle *query =
3212 sp_style_new ();
3214 int result_numbers =
3215 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3217 SPCSSAttr *css = sp_repr_css_attr_new ();
3218 sp_repr_css_set_property (css, "font-family", family);
3220 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3221 if (result_numbers == QUERY_STYLE_NOTHING)
3222 {
3223 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3224 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3225 }
3226 else
3227 {
3228 sp_desktop_set_style (desktop, css, true, true);
3229 }
3231 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3232 _("Text: Change font family"));
3233 sp_repr_css_attr_unref (css);
3234 free (family);
3235 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3237 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3238 }
3240 void
3241 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
3242 GObject *tbl)
3243 {
3244 const char *family = gtk_entry_get_text (entry);
3246 try {
3247 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3248 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3249 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3250 gtk_tree_selection_select_path (selection, path.gobj());
3251 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3252 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3253 } catch (...) {
3254 if (family && strlen (family))
3255 {
3256 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3257 }
3258 }
3259 }
3261 void
3262 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
3263 gpointer data)
3264 {
3265 if (g_object_get_data (G_OBJECT (button), "block")) return;
3266 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3267 int prop = GPOINTER_TO_INT(data);
3269 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3270 SPCSSAttr *css = sp_repr_css_attr_new ();
3272 switch (prop)
3273 {
3274 case 0:
3275 {
3276 sp_repr_css_set_property (css, "text-anchor", "start");
3277 sp_repr_css_set_property (css, "text-align", "start");
3278 break;
3279 }
3280 case 1:
3281 {
3282 sp_repr_css_set_property (css, "text-anchor", "middle");
3283 sp_repr_css_set_property (css, "text-align", "center");
3284 break;
3285 }
3287 case 2:
3288 {
3289 sp_repr_css_set_property (css, "text-anchor", "end");
3290 sp_repr_css_set_property (css, "text-align", "end");
3291 break;
3292 }
3294 case 3:
3295 {
3296 sp_repr_css_set_property (css, "text-anchor", "start");
3297 sp_repr_css_set_property (css, "text-align", "justify");
3298 break;
3299 }
3300 }
3302 SPStyle *query =
3303 sp_style_new ();
3304 int result_numbers =
3305 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3307 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3308 if (result_numbers == QUERY_STYLE_NOTHING)
3309 {
3310 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3311 }
3313 sp_desktop_set_style (desktop, css, true, true);
3314 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3315 _("Text: Change alignment"));
3316 sp_repr_css_attr_unref (css);
3318 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3319 }
3321 void
3322 sp_text_toolbox_style_toggled (GtkToggleButton *button,
3323 gpointer data)
3324 {
3325 if (g_object_get_data (G_OBJECT (button), "block")) return;
3327 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3328 SPCSSAttr *css = sp_repr_css_attr_new ();
3329 int prop = GPOINTER_TO_INT(data);
3330 bool active = gtk_toggle_button_get_active (button);
3333 switch (prop)
3334 {
3335 case 0:
3336 {
3337 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
3338 break;
3339 }
3341 case 1:
3342 {
3343 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
3344 break;
3345 }
3346 }
3348 SPStyle *query =
3349 sp_style_new ();
3350 int result_numbers =
3351 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3353 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3354 if (result_numbers == QUERY_STYLE_NOTHING)
3355 {
3356 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3357 }
3359 sp_desktop_set_style (desktop, css, true, true);
3360 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3361 _("Text: Change font style"));
3362 sp_repr_css_attr_unref (css);
3364 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3365 }
3367 void
3368 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
3369 gpointer data)
3370 {
3371 if (g_object_get_data (G_OBJECT (button), "block")) {
3372 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3373 return;
3374 }
3376 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3377 SPCSSAttr *css = sp_repr_css_attr_new ();
3378 int prop = GPOINTER_TO_INT(data);
3380 switch (prop)
3381 {
3382 case 0:
3383 {
3384 sp_repr_css_set_property (css, "writing-mode", "lr");
3385 break;
3386 }
3388 case 1:
3389 {
3390 sp_repr_css_set_property (css, "writing-mode", "tb");
3391 break;
3392 }
3393 }
3395 SPStyle *query =
3396 sp_style_new ();
3397 int result_numbers =
3398 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3400 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3401 if (result_numbers == QUERY_STYLE_NOTHING)
3402 {
3403 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3404 }
3406 sp_desktop_set_style (desktop, css, true, true);
3407 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3408 _("Text: Change orientation"));
3409 sp_repr_css_attr_unref (css);
3411 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3412 }
3414 gboolean
3415 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3416 {
3417 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3418 if (!desktop) return FALSE;
3420 switch (get_group0_keyval (event)) {
3421 case GDK_Escape: // defocus
3422 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3423 return TRUE; // I consumed the event
3424 break;
3425 case GDK_Return: // defocus
3426 case GDK_KP_Enter:
3427 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3428 return TRUE; // I consumed the event
3429 break;
3430 }
3431 return FALSE;
3432 }
3434 gboolean
3435 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3436 {
3437 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3438 if (!desktop) return FALSE;
3440 switch (get_group0_keyval (event)) {
3441 case GDK_Escape: // defocus
3442 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3443 sp_text_toolbox_selection_changed (NULL, tbl); // update
3444 return TRUE; // I consumed the event
3445 break;
3446 }
3447 return FALSE;
3448 }
3450 gboolean
3451 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3452 {
3453 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3454 if (!desktop) return FALSE;
3456 switch (get_group0_keyval (event)) {
3457 case GDK_Escape: // defocus
3458 gtk_widget_hide (w);
3459 visible = false;
3460 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3461 return TRUE; // I consumed the event
3462 break;
3463 }
3464 return FALSE;
3465 }
3468 void
3469 sp_text_toolbox_size_changed (GtkComboBox *cbox,
3470 GObject *tbl)
3471 {
3472 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3474 if (g_object_get_data (tbl, "size-block")) return;
3476 #if GTK_CHECK_VERSION(2,6,0)
3477 char *text = gtk_combo_box_get_active_text (cbox);
3478 #else // GTK_CHECK_VERSION(2,6,0)
3479 GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3480 GtkTreeIter iter;
3481 char *text = NULL;
3483 if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3484 gtk_tree_model_get (model, &iter, 0, &text, -1);
3485 #endif // GTK_CHECK_VERSION(2,6,0)
3487 SPCSSAttr *css = sp_repr_css_attr_new ();
3488 sp_repr_css_set_property (css, "font-size", text);
3489 free (text);
3491 SPStyle *query =
3492 sp_style_new ();
3493 int result_numbers =
3494 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3496 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3497 if (result_numbers == QUERY_STYLE_NOTHING)
3498 {
3499 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3500 }
3502 sp_desktop_set_style (desktop, css, true, true);
3503 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
3504 _("Text: Change font size"));
3505 sp_repr_css_attr_unref (css);
3508 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3509 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3510 }
3512 void
3513 sp_text_toolbox_text_popdown_clicked (GtkButton *button,
3514 GObject *tbl)
3515 {
3516 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3517 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3518 int x, y;
3520 if (!visible)
3521 {
3522 gdk_window_get_origin (widget->window, &x, &y);
3523 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
3524 gtk_widget_show_all (popdown);
3526 gdk_pointer_grab (widget->window, TRUE,
3527 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3528 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3529 GDK_POINTER_MOTION_MASK),
3530 NULL, NULL, GDK_CURRENT_TIME);
3532 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3534 visible = true;
3535 }
3536 else
3537 {
3538 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3539 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3540 gtk_widget_hide (popdown);
3541 visible = false;
3542 }
3543 }
3545 gboolean
3546 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
3547 GdkEventFocus *event,
3548 GObject *tbl)
3549 {
3550 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3551 return FALSE;
3552 }
3554 gboolean
3555 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
3556 GdkEventFocus *event,
3557 GObject *tbl)
3558 {
3559 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3561 gtk_widget_hide (popdown);
3562 visible = false;
3563 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3564 return TRUE;
3565 }
3567 void
3568 cell_data_func (GtkTreeViewColumn *column,
3569 GtkCellRenderer *cell,
3570 GtkTreeModel *tree_model,
3571 GtkTreeIter *iter,
3572 gpointer data)
3573 {
3574 char *family,
3575 *family_escaped,
3576 *sample_escaped;
3578 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3580 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3582 family_escaped = g_markup_escape_text (family, -1);
3583 sample_escaped = g_markup_escape_text (sample, -1);
3585 std::stringstream markup;
3586 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3587 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3589 free (family);
3590 free (family_escaped);
3591 free (sample_escaped);
3592 }
3594 static void delete_completion(GObject *obj, GtkWidget *entry) {
3595 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3596 if (completion) {
3597 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3598 g_object_unref (completion);
3599 }
3600 }
3602 GtkWidget*
3603 sp_text_toolbox_new (SPDesktop *desktop)
3604 {
3605 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
3607 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3608 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3610 GtkTooltips *tt = gtk_tooltips_new();
3611 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3613 ////////////Family
3614 //Window
3615 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3616 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3618 //Entry
3619 GtkWidget *entry = gtk_entry_new ();
3620 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3621 GtkEntryCompletion *completion = gtk_entry_completion_new ();
3622 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3623 gtk_entry_completion_set_text_column (completion, 0);
3624 gtk_entry_completion_set_minimum_key_length (completion, 1);
3625 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3626 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3627 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
3628 aux_toolbox_space (tbl, 1);
3629 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3630 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
3632 //Button
3633 GtkWidget *button = gtk_button_new ();
3634 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3635 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3637 //Popdown
3638 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
3639 GtkWidget *treeview = gtk_tree_view_new ();
3641 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
3642 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
3643 gtk_tree_view_column_pack_start (column, cell, FALSE);
3644 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3645 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3646 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3648 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3649 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3650 #if GTK_CHECK_VERSION(2,6,0)
3651 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3652 #endif // GTK_CHECK_VERSION(2,6,0)
3654 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3656 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
3657 gtk_container_add (GTK_CONTAINER (sw), treeview);
3659 gtk_container_add (GTK_CONTAINER (window), sw);
3660 gtk_widget_set_size_request (window, 300, 450);
3662 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3663 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3664 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3666 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3668 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3669 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3671 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3672 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3674 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3675 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3676 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3677 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3678 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3680 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3681 aux_toolbox_space (tbl, 1);
3682 GtkWidget *box = gtk_event_box_new ();
3683 gtk_container_add (GTK_CONTAINER (box), image);
3684 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3685 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3686 GtkTooltips *tooltips = gtk_tooltips_new ();
3687 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3688 gtk_widget_hide (GTK_WIDGET (box));
3689 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3691 ////////////Size
3692 const char *sizes[] = {
3693 "4", "6", "8", "9", "10", "11", "12", "13", "14",
3694 "16", "18", "20", "22", "24", "28",
3695 "32", "36", "40", "48", "56", "64", "72", "144"
3696 };
3698 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3699 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3700 gtk_widget_set_size_request (cbox, 80, -1);
3701 aux_toolbox_space (tbl, 1);
3702 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3703 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3704 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3705 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3707 //spacer
3708 aux_toolbox_space (tbl, 4);
3709 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3711 ////////////Text anchor
3712 GtkWidget *group = gtk_radio_button_new (NULL);
3713 GtkWidget *row = gtk_hbox_new (FALSE, 4);
3714 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3716 // left
3717 GtkWidget *rbutton = group;
3718 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3719 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3720 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3722 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3723 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
3724 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3725 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3727 // center
3728 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3729 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3730 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3731 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3733 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3734 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
3735 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
3736 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3738 // right
3739 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3740 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3741 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3742 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3744 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3745 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
3746 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3747 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3749 // fill
3750 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3751 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3752 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3753 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3755 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3756 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
3757 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3758 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3760 aux_toolbox_space (tbl, 1);
3761 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3763 //spacer
3764 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3766 ////////////Text style
3767 row = gtk_hbox_new (FALSE, 4);
3769 // bold
3770 rbutton = gtk_toggle_button_new ();
3771 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3772 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3773 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3774 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3776 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3777 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
3778 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3780 // italic
3781 rbutton = gtk_toggle_button_new ();
3782 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3783 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3784 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3785 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3787 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3788 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
3789 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
3791 aux_toolbox_space (tbl, 1);
3792 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3794 //spacer
3795 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3797 ////////////Text orientation
3798 group = gtk_radio_button_new (NULL);
3799 row = gtk_hbox_new (FALSE, 4);
3800 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
3802 // horizontal
3803 rbutton = group;
3804 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3805 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
3806 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3807 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
3809 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3810 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
3811 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
3813 // vertical
3814 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3815 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3816 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
3817 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3818 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
3820 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3821 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
3822 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
3823 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3826 //watch selection
3827 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
3829 sigc::connection *c_selection_changed =
3830 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
3831 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
3832 pool->add_connection ("selection-changed", c_selection_changed);
3834 sigc::connection *c_selection_modified =
3835 new sigc::connection (sp_desktop_selection (desktop)->connectModified
3836 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
3837 pool->add_connection ("selection-modified", c_selection_modified);
3839 sigc::connection *c_subselection_changed =
3840 new sigc::connection (desktop->connectToolSubselectionChanged
3841 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
3842 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
3844 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
3847 #if 0
3848 // horizontal
3849 {
3850 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
3851 GtkWidget *b = group = gtk_radio_button_new (NULL);
3852 gtk_container_add (GTK_CONTAINER (b), px);
3853 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
3854 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3855 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3856 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3857 }
3859 // vertical
3860 {
3861 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
3862 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3863 gtk_container_add (GTK_CONTAINER (b), px);
3864 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
3865 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
3866 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
3867 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
3868 }
3870 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3872 // letter spacing
3873 {
3874 {
3875 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
3876 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3877 gtk_container_add (GTK_CONTAINER (hb), image);
3878 gtk_widget_show(image);
3879 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3880 }
3882 {
3883 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
3884 "tools.text", "letter_spacing", 0.0,
3885 us, tbl, FALSE, NULL,
3886 -1000.0, 1000.0, 0.1, 0.1,
3887 sp_text_letter_changed, 0.1, 1);
3888 gtk_widget_set_size_request (hb, 45, 6);
3889 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3890 }
3891 }
3893 // line spacing
3894 {
3895 {
3896 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
3897 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3898 gtk_container_add (GTK_CONTAINER (hb), image);
3899 gtk_widget_show(image);
3900 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3901 }
3903 {
3904 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
3905 "tools.text", "line_spacing", 0,
3906 us, tbl, FALSE, NULL,
3907 -1000.0, 1000.0, 0.1, 0.1,
3908 sp_text_line_changed, 0.1, 1);
3909 gtk_widget_set_size_request (hb, 45, 0);
3910 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
3911 }
3912 }
3914 {
3915 // horizontal kerning/vertical kerning units menu: create
3916 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
3917 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
3918 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
3920 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3922 // horizontal kerning
3923 {
3924 {
3925 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
3926 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3927 gtk_container_add (GTK_CONTAINER (hb), image);
3928 gtk_widget_show(image);
3929 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3930 }
3932 {
3933 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
3934 "tools.text", "horizontal_kerning", 0,
3935 us, tbl, FALSE, NULL,
3936 -100.00, 100.00, 0.01, 0.1,
3937 sp_text_horiz_kern_changed);
3938 gtk_widget_set_size_request (hb, 45, 0);
3939 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3940 }
3941 }
3943 // vertical kerning
3944 {
3945 {
3946 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
3947 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3948 gtk_container_add (GTK_CONTAINER (hb), image);
3949 gtk_widget_show(image);
3950 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3951 }
3953 {
3954 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
3955 "tools.text", "vertical_kerning", 0,
3956 us, tbl, FALSE, NULL,
3957 -100.00, 100.00, 0.01, 0.1,
3958 sp_text_vert_kern_changed);
3959 gtk_widget_set_size_request (hb, 45, 0);
3960 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
3961 }
3962 }
3964 // add the units menu
3965 gtk_widget_show(us);
3966 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
3967 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
3968 }
3970 // letter rotation
3971 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3972 {
3973 {
3974 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
3975 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3976 gtk_container_add (GTK_CONTAINER (hb), image);
3977 gtk_widget_show(image);
3978 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
3979 }
3980 {
3981 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
3982 "tools.text", "letter_rotation", 0,
3983 us, tbl, FALSE, NULL,
3984 -180.0, 180.0, 0.1, 0.1,
3985 sp_text_letter_rotation_changed, 0.1, 1);
3986 gtk_widget_set_size_request (hb, 45, 0);
3987 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
3988 }
3989 // rotation degree label
3990 {
3991 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
3992 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
3993 }
3994 }
3996 // Remove Manual Kerns
3997 {
3998 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
3999 GtkWidget *button = gtk_button_new ();
4000 gtk_container_add (GTK_CONTAINER (button), px);
4001 gtk_widget_show(button);
4002 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4003 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4004 gtk_widget_set_sensitive(button, TRUE);
4005 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4006 }
4007 #endif
4009 gtk_widget_show_all (tbl);
4010 return tbl;
4012 } // end of sp_text_toolbox_new()
4014 }//<unnamed> namespace
4017 //#########################
4018 //## Connector Toolbox ##
4019 //#########################
4021 static void sp_connector_path_set_avoid(void)
4022 {
4023 cc_selection_set_avoid(true);
4024 }
4027 static void sp_connector_path_set_ignore(void)
4028 {
4029 cc_selection_set_avoid(false);
4030 }
4034 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
4035 {
4036 // quit if run by the _changed callbacks
4037 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4038 return;
4039 }
4041 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
4042 "desktop");
4043 SPDocument *doc = sp_desktop_document(desktop);
4045 if (!sp_document_get_undo_sensitive(doc))
4046 {
4047 return;
4048 }
4050 // in turn, prevent callbacks from responding
4051 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
4053 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4055 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4056 SP_OBJECT(desktop->namedview)->updateRepr();
4058 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4059 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4060 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4061 NR::Matrix m = NR::identity();
4062 avoid_item_move(&m, item);
4063 }
4065 if (items) {
4066 g_slist_free(items);
4067 }
4069 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4070 _("Change connector spacing"));
4072 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
4074 spinbutton_defocus(GTK_OBJECT(tbl));
4075 }
4077 static void sp_connector_graph_layout(void)
4078 {
4079 if (!SP_ACTIVE_DESKTOP) return;
4081 // hack for clones, see comment in align-and-distribute.cpp
4082 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4083 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4085 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4087 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4089 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4090 }
4092 static void
4093 sp_directed_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4094 {
4095 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4096 prefs_set_string_attribute("tools.connector", "directedlayout",
4097 "true");
4098 } else {
4099 prefs_set_string_attribute("tools.connector", "directedlayout",
4100 "false");
4101 }
4102 }
4103 static void
4104 sp_nooverlaps_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4105 {
4106 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4107 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4108 "true");
4109 } else {
4110 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4111 "false");
4112 }
4113 }
4116 static void connector_length_changed(GtkAdjustment *adj, GtkWidget *tbl)
4117 {
4118 prefs_set_double_attribute("tools.connector", "length", adj->value);
4119 spinbutton_defocus(GTK_OBJECT(tbl));
4120 }
4122 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4123 gchar const *name, gchar const *old_value, gchar const *new_value,
4124 bool is_interactive, gpointer data)
4125 {
4126 GtkWidget *tbl = GTK_WIDGET(data);
4128 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4129 return;
4130 }
4131 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4132 return;
4133 }
4135 GtkAdjustment *adj = (GtkAdjustment*)
4136 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4137 gdouble spacing = defaultConnSpacing;
4138 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4140 gtk_adjustment_set_value(adj, spacing);
4141 }
4144 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4145 NULL, /* child_added */
4146 NULL, /* child_removed */
4147 connector_tb_event_attr_changed,
4148 NULL, /* content_changed */
4149 NULL /* order_changed */
4150 };
4153 static GtkWidget *
4154 sp_connector_toolbox_new(SPDesktop *desktop)
4155 {
4156 GtkTooltips *tt = gtk_tooltips_new();
4157 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
4159 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4160 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4162 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4163 AUX_BETWEEN_BUTTON_GROUPS);
4165 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4166 "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
4167 tt, _("Make connectors avoid selected objects"));
4169 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4170 "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
4171 tt, _("Make connectors ignore selected objects"));
4173 // interval
4174 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4175 AUX_BETWEEN_BUTTON_GROUPS);
4177 // Spacing spinbox
4178 {
4179 GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
4180 _("The amount of space left around objects by auto-routing connectors"),
4181 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
4182 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
4183 connector_spacing_changed, 1, 0);
4185 gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
4186 AUX_SPACING);
4187 }
4188 // Graph (connector network) layout
4189 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4190 "graph_layout", GTK_SIGNAL_FUNC(sp_connector_graph_layout),
4191 tt, _("Nicely arrange selected connector network"));
4192 // Default connector length spinbox
4193 {
4194 GtkWidget *connector_length = sp_tb_spinbutton(_("Length:"),
4195 _("Ideal length for connectors when layout is applied"),
4196 "tools.connector", "length", 100, NULL, tbl, TRUE,
4197 "inkscape:connector-length", 10, 1000, 10.0, 100.0,
4198 connector_length_changed, 1, 0);
4200 gtk_box_pack_start(GTK_BOX(tbl), connector_length, FALSE, FALSE,
4201 AUX_SPACING);
4202 }
4203 gchar const *tbuttonstate;
4204 // Directed edges toggle button
4205 {
4206 GtkWidget *tbutton = gtk_toggle_button_new ();
4207 gtk_button_set_relief (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4208 gtk_container_add (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "directed_graph"));
4209 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4210 gtk_tooltips_set_tip(tt, tbutton, _("Make connectors with end-markers (arrows) point downwards"), NULL);
4212 gtk_box_pack_start (GTK_BOX (tbl), tbutton, FALSE, FALSE, 0);
4213 g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_directed_graph_layout_toggled), tbl);
4214 tbuttonstate = prefs_get_string_attribute("tools.connector", "directedlayout");
4215 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4216 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4217 }
4218 // Avoid overlaps toggle button
4219 {
4220 GtkWidget *tbutton = gtk_toggle_button_new ();
4221 gtk_button_set_relief (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4222 gtk_container_add (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "remove_overlaps"));
4223 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4224 gtk_tooltips_set_tip(tt, tbutton, _("Do not allow overlapping shapes"), NULL);
4226 gtk_box_pack_start (GTK_BOX (tbl), tbutton, FALSE, FALSE, 0);
4227 g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_nooverlaps_graph_layout_toggled), tbl);
4228 tbuttonstate = prefs_get_string_attribute("tools.connector", "avoidoverlaplayout");
4229 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4230 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4231 }
4233 gtk_widget_show_all(tbl);
4234 sp_set_font_size_smaller (tbl);
4236 // Code to watch for changes to the connector-spacing attribute in
4237 // the XML.
4238 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4239 g_assert(repr != NULL);
4241 purge_repr_listener( G_OBJECT(tbl), G_OBJECT(tbl) );
4243 if (repr) {
4244 g_object_set_data(G_OBJECT(tbl), "repr", repr);
4245 Inkscape::GC::anchor(repr);
4246 sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
4247 sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
4248 }
4250 return tbl;
4252 } // end of sp_connector_toolbox_new()
4254 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* tbl)
4255 {
4256 gint channels = ege_select_one_action_get_active( act );
4257 flood_channels_set_channels( channels );
4258 }
4260 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject *tbl)
4261 {
4262 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4263 }
4265 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
4266 {
4267 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
4268 SPUnit const *unit = tracker->getActiveUnit();
4271 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
4272 }
4274 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4275 {
4276 EgeAdjustmentAction* eact = 0;
4278 {
4279 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4281 GList* items = 0;
4282 gint count = 0;
4283 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
4284 {
4285 GtkTreeIter iter;
4286 gtk_list_store_append( model, &iter );
4287 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4288 count++;
4289 }
4290 g_list_free( items );
4291 items = 0;
4292 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by:"), _(""), NULL, GTK_TREE_MODEL(model) );
4293 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
4294 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
4295 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
4296 }
4298 // Spacing spinbox
4299 {
4300 eact = create_adjustment_action(
4301 "ThresholdAction",
4302 _("Threshold:"),
4303 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
4304 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
4305 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
4306 0, 0, 0,
4307 paintbucket_threshold_changed, 1, 0 );
4309 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4310 }
4312 // Create the units menu.
4313 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
4314 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
4315 g_object_set_data( holder, "tracker", tracker );
4316 {
4317 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), _("") );
4318 gtk_action_group_add_action( mainActions, act );
4319 }
4321 // Offset spinbox
4322 {
4323 eact = create_adjustment_action(
4324 "OffsetAction",
4325 _("Grow/shrink by:"),
4326 _("The amount to grow (positive) or shrink (negative) the created fill path"),
4327 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
4328 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
4329 0, 0, 0,
4330 paintbucket_offset_changed, 1, 2);
4331 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
4333 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4334 }
4335 }
4337 /*
4338 Local Variables:
4339 mode:c++
4340 c-file-style:"stroustrup"
4341 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4342 indent-tabs-mode:nil
4343 fill-column:99
4344 End:
4345 */
4346 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :