7296ae9acf1a08db877535e5ad3c3c0371d4999b
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 GtkWidget *sp_dropper_toolbox_new(SPDesktop *desktop);
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", sp_dropper_toolbox_new, 0, 0,
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>"
328 "</ui>"
329 ;
331 static GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop );
333 static void toolbox_set_desktop (GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection*);
335 static void setup_tool_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
336 static void update_tool_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
338 static void setup_aux_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
339 static void update_aux_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
341 static void setup_commands_toolbox (GtkWidget *toolbox, SPDesktop *desktop);
342 static void update_commands_toolbox (SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox);
344 /* Global text entry widgets necessary for update */
345 /* GtkWidget *dropper_rgb_entry,
346 *dropper_opacity_entry ; */
347 // should be made a private member once this is converted to class
349 static void delete_connection(GObject *obj, sigc::connection *connection) {
350 connection->disconnect();
351 delete connection;
352 }
354 static GtkWidget *
355 sp_toolbox_button_new(GtkWidget *t, Inkscape::IconSize size, gchar const *pxname, GtkSignalFunc handler,
356 GtkTooltips *tt, gchar const *tip)
357 {
358 GtkWidget *b = sp_button_new_from_data(size, SP_BUTTON_TYPE_NORMAL, NULL, pxname, tip, tt);
359 gtk_widget_show(b);
360 if (handler) gtk_signal_connect(GTK_OBJECT(b), "clicked", handler, NULL);
361 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
363 return b;
364 }
366 GtkWidget *
367 sp_toolbox_button_new_from_verb_with_doubleclick(GtkWidget *t, Inkscape::IconSize size, SPButtonType type,
368 Inkscape::Verb *verb, Inkscape::Verb *doubleclick_verb,
369 Inkscape::UI::View::View *view, GtkTooltips *tt)
370 {
371 SPAction *action = verb->get_action(view);
372 if (!action) return NULL;
374 SPAction *doubleclick_action;
375 if (doubleclick_verb)
376 doubleclick_action = doubleclick_verb->get_action(view);
377 else
378 doubleclick_action = NULL;
380 /* fixme: Handle sensitive/unsensitive */
381 /* fixme: Implement sp_button_new_from_action */
382 GtkWidget *b = sp_button_new(size, type, action, doubleclick_action, tt);
383 gtk_widget_show(b);
384 gtk_box_pack_start(GTK_BOX(t), b, FALSE, FALSE, 0);
386 return b;
387 }
389 GtkWidget *sp_toolbox_button_new_from_verb(GtkWidget *t, Inkscape::IconSize size, SPButtonType type, Inkscape::Verb *verb,
390 Inkscape::UI::View::View *view, GtkTooltips *tt)
391 {
392 return sp_toolbox_button_new_from_verb_with_doubleclick(t, size, type, verb, NULL, view, tt);
393 }
395 GtkWidget * sp_toolbox_button_normal_new_from_verb(GtkWidget *t, Inkscape::IconSize size, Inkscape::Verb *verb,
396 Inkscape::UI::View::View *view, GtkTooltips *tt)
397 {
398 return sp_toolbox_button_new_from_verb(t, size, SP_BUTTON_TYPE_NORMAL, verb, view, tt);
399 }
402 static void trigger_sp_action( GtkAction* act, gpointer user_data )
403 {
404 SPAction* targetAction = SP_ACTION(user_data);
405 if ( targetAction ) {
406 sp_action_perform( targetAction, NULL );
407 }
408 }
410 static void sp_action_action_set_sensitive (SPAction *action, unsigned int sensitive, void *data)
411 {
412 if ( data ) {
413 GtkAction* act = GTK_ACTION(data);
414 gtk_action_set_sensitive( act, sensitive );
415 }
416 }
418 static SPActionEventVector action_event_vector = {
419 {NULL},
420 NULL,
421 NULL,
422 sp_action_action_set_sensitive,
423 NULL,
424 NULL
425 };
427 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
428 {
429 GtkAction* act = 0;
431 SPAction* targetAction = verb->get_action(view);
432 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
433 act = GTK_ACTION(inky);
434 gtk_action_set_sensitive( act, targetAction->sensitive );
436 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
438 SPAction*rebound = dynamic_cast<SPAction *>( nr_object_ref( dynamic_cast<NRObject *>(targetAction) ) );
439 nr_active_object_add_listener( (NRActiveObject *)rebound, (NRObjectEventVector *)&action_event_vector, sizeof(SPActionEventVector), inky );
441 return act;
442 }
444 GtkActionGroup* create_or_fetch_actions( SPDesktop* desktop )
445 {
446 Inkscape::UI::View::View *view = desktop;
447 gint verbsToUse[] = {
448 // disabled until we have icons for them:
449 //find
450 //SP_VERB_EDIT_TILE,
451 //SP_VERB_EDIT_UNTILE,
452 SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
453 SP_VERB_DIALOG_DISPLAY,
454 SP_VERB_DIALOG_FILL_STROKE,
455 SP_VERB_DIALOG_NAMEDVIEW,
456 SP_VERB_DIALOG_TEXT,
457 SP_VERB_DIALOG_XML_EDITOR,
458 SP_VERB_EDIT_CLONE,
459 SP_VERB_EDIT_COPY,
460 SP_VERB_EDIT_CUT,
461 SP_VERB_EDIT_DUPLICATE,
462 SP_VERB_EDIT_PASTE,
463 SP_VERB_EDIT_REDO,
464 SP_VERB_EDIT_UNDO,
465 SP_VERB_EDIT_UNLINK_CLONE,
466 SP_VERB_FILE_EXPORT,
467 SP_VERB_FILE_IMPORT,
468 SP_VERB_FILE_NEW,
469 SP_VERB_FILE_OPEN,
470 SP_VERB_FILE_PRINT,
471 SP_VERB_FILE_SAVE,
472 SP_VERB_OBJECT_TO_CURVE,
473 SP_VERB_SELECTION_GROUP,
474 SP_VERB_SELECTION_OUTLINE,
475 SP_VERB_SELECTION_UNGROUP,
476 SP_VERB_ZOOM_1_1,
477 SP_VERB_ZOOM_1_2,
478 SP_VERB_ZOOM_2_1,
479 SP_VERB_ZOOM_DRAWING,
480 SP_VERB_ZOOM_IN,
481 SP_VERB_ZOOM_NEXT,
482 SP_VERB_ZOOM_OUT,
483 SP_VERB_ZOOM_PAGE,
484 SP_VERB_ZOOM_PAGE_WIDTH,
485 SP_VERB_ZOOM_PREV,
486 SP_VERB_ZOOM_SELECTION,
487 };
489 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
490 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
492 static std::map<SPDesktop*, GtkActionGroup*> groups;
493 GtkActionGroup* mainActions = 0;
494 if ( groups.find(desktop) != groups.end() ) {
495 mainActions = groups[desktop];
496 }
498 if ( !mainActions ) {
499 mainActions = gtk_action_group_new("main");
500 groups[desktop] = mainActions;
501 }
503 for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
504 Inkscape::Verb* verb = Inkscape::Verb::get(verbsToUse[i]);
505 if ( verb ) {
506 if ( !gtk_action_group_get_action( mainActions, verb->get_id() ) ) {
507 GtkAction* act = create_action_for_verb( verb, view, toolboxSize );
508 gtk_action_group_add_action( mainActions, act );
509 }
510 }
511 }
513 return mainActions;
514 }
517 GtkWidget *
518 sp_tool_toolbox_new()
519 {
520 GtkTooltips *tt = gtk_tooltips_new();
521 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
523 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
524 g_object_set_data(G_OBJECT(tb), "tooltips", tt);
526 gtk_widget_set_sensitive(tb, FALSE);
528 GtkWidget *hb = gtk_handle_box_new();
529 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_TOP);
530 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
531 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
533 gtk_container_add(GTK_CONTAINER(hb), tb);
534 gtk_widget_show(GTK_WIDGET(tb));
536 sigc::connection* conn = new sigc::connection;
537 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
539 return hb;
540 }
542 static void
543 aux_toolbox_attached(GtkHandleBox *toolbox, GtkWidget *child)
544 {
545 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(FALSE));
546 gtk_widget_queue_resize(child);
547 }
549 static void
550 aux_toolbox_detached(GtkHandleBox *toolbox, GtkWidget *child)
551 {
552 g_object_set_data(G_OBJECT(child), "is_detached", GINT_TO_POINTER(TRUE));
553 gtk_widget_queue_resize(child);
554 }
556 GtkWidget *
557 sp_aux_toolbox_new()
558 {
559 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
561 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
562 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
563 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
564 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
565 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
567 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
568 g_object_set_data(G_OBJECT(tb), "top_spacer", tb_s);
570 gtk_widget_set_sensitive(tb, FALSE);
572 GtkWidget *hb = gtk_handle_box_new();
573 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
574 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
575 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
577 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
578 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
580 gtk_container_add(GTK_CONTAINER(hb), tb);
581 gtk_widget_show(GTK_WIDGET(tb));
583 sigc::connection* conn = new sigc::connection;
584 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
586 return hb;
587 }
589 //####################################
590 //# Commands Bar
591 //####################################
593 GtkWidget *
594 sp_commands_toolbox_new()
595 {
596 GtkWidget *tb = gtk_vbox_new(FALSE, 0);
598 GtkWidget *tb_s = gtk_vbox_new(FALSE, 0);
599 GtkWidget *tb_e = gtk_vbox_new(FALSE, 0);
600 gtk_box_set_spacing(GTK_BOX(tb), AUX_SPACING);
601 gtk_box_pack_start(GTK_BOX(tb), GTK_WIDGET(tb_s), FALSE, FALSE, 0);
602 gtk_box_pack_end(GTK_BOX(tb), GTK_WIDGET(tb_e), FALSE, FALSE, 0);
604 g_object_set_data(G_OBJECT(tb), "desktop", NULL);
605 gtk_widget_set_sensitive(tb, FALSE);
607 GtkWidget *hb = gtk_handle_box_new();
608 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
609 gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(hb), GTK_SHADOW_OUT);
610 gtk_handle_box_set_snap_edge(GTK_HANDLE_BOX(hb), GTK_POS_LEFT);
612 g_signal_connect(G_OBJECT(hb), "child_attached", G_CALLBACK(aux_toolbox_attached), (gpointer)tb);
613 g_signal_connect(G_OBJECT(hb), "child_detached", G_CALLBACK(aux_toolbox_detached), (gpointer)tb);
615 gtk_container_add(GTK_CONTAINER(hb), tb);
616 gtk_widget_show(GTK_WIDGET(tb));
618 sigc::connection* conn = new sigc::connection;
619 g_object_set_data(G_OBJECT(hb), "event_context_connection", conn);
621 return hb;
622 }
625 //####################################
626 //# node editing callbacks
627 //####################################
629 void
630 sp_node_path_edit_add(void)
631 {
632 sp_node_selected_add_node();
633 }
635 void
636 sp_node_path_edit_delete(void)
637 {
638 sp_node_selected_delete();
639 }
641 void
642 sp_node_path_edit_delete_segment(void)
643 {
644 sp_node_selected_delete_segment();
645 }
647 void
648 sp_node_path_edit_break(void)
649 {
650 sp_node_selected_break();
651 }
653 void
654 sp_node_path_edit_join(void)
655 {
656 sp_node_selected_join();
657 }
659 void
660 sp_node_path_edit_join_segment(void)
661 {
662 sp_node_selected_join_segment();
663 }
665 void
666 sp_node_path_edit_toline(void)
667 {
668 sp_node_selected_set_line_type(NR_LINETO);
669 }
671 void
672 sp_node_path_edit_tocurve(void)
673 {
674 sp_node_selected_set_line_type(NR_CURVETO);
675 }
677 void
678 sp_node_path_edit_cusp(void)
679 {
680 sp_node_selected_set_type(Inkscape::NodePath::NODE_CUSP);
681 }
683 void
684 sp_node_path_edit_smooth(void)
685 {
686 sp_node_selected_set_type(Inkscape::NodePath::NODE_SMOOTH);
687 }
689 void
690 sp_node_path_edit_symmetrical(void)
691 {
692 sp_node_selected_set_type(Inkscape::NodePath::NODE_SYMM);
693 }
695 static void toggle_show_handles (GtkToggleAction *act, gpointer data) {
696 bool show = gtk_toggle_action_get_active( act );
697 prefs_set_int_attribute ("tools.nodes", "show_handles", show ? 1 : 0);
698 sp_nodepath_show_handles(show);
699 }
701 //################################
702 //## Node Editing Toolbox ##
703 //################################
705 static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
706 {
707 {
708 InkAction* inky = ink_action_new( "NodeInsertAction",
709 _("Insert"),
710 _("Insert new nodes into selected segments"),
711 "node_insert",
712 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
713 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_add), 0 );
714 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
715 }
717 {
718 InkAction* inky = ink_action_new( "NodeDeleteAction",
719 _("Delete"),
720 _("Delete selected nodes"),
721 "node_delete",
722 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
723 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete), 0 );
724 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
725 }
727 {
728 InkAction* inky = ink_action_new( "NodeJoinAction",
729 _("Join"),
730 _("Join selected endnodes"),
731 "node_join",
732 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
733 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join), 0 );
734 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
735 }
737 {
738 InkAction* inky = ink_action_new( "NodeJoinSegmentAction",
739 _("Join Segment"),
740 _("Join selected endnodes with a new segment"),
741 "node_join_segment",
742 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
743 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_join_segment), 0 );
744 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
745 }
747 {
748 InkAction* inky = ink_action_new( "NodeDeleteSegmentAction",
749 _("Delete Segment"),
750 _("Split path between two non-endpoint nodes"),
751 "node_delete_segment",
752 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
753 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_delete_segment), 0 );
754 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
755 }
757 {
758 InkAction* inky = ink_action_new( "NodeBreakAction",
759 _("Node Break"),
760 _("Break path at selected nodes"),
761 "node_break",
762 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
763 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_break), 0 );
764 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
765 }
767 {
768 InkAction* inky = ink_action_new( "NodeCuspAction",
769 _("Node Cusp"),
770 _("Make selected nodes corner"),
771 "node_cusp",
772 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
773 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_cusp), 0 );
774 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
775 }
777 {
778 InkAction* inky = ink_action_new( "NodeSmoothAction",
779 _("Node Smooth"),
780 _("Make selected nodes smooth"),
781 "node_smooth",
782 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
783 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_smooth), 0 );
784 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
785 }
787 {
788 InkAction* inky = ink_action_new( "NodeSymmetricAction",
789 _("Node Symmetric"),
790 _("Make selected nodes symmetric"),
791 "node_symmetric",
792 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
793 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_symmetrical), 0 );
794 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
795 }
797 {
798 InkAction* inky = ink_action_new( "NodeLineAction",
799 _("Node Line"),
800 _("Make selected segments lines"),
801 "node_line",
802 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
803 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_toline), 0 );
804 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
805 }
807 {
808 InkAction* inky = ink_action_new( "NodeCurveAction",
809 _("Node Curve"),
810 _("Make selected segments curves"),
811 "node_curve",
812 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
813 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_node_path_edit_tocurve), 0 );
814 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
815 }
817 {
818 InkToggleAction* act = ink_toggle_action_new( "NodesShowHandlesAction",
819 _("Show Handles"),
820 _("Show the Bezier handles of selected nodes"),
821 "nodes_show_handles",
822 Inkscape::ICON_SIZE_DECORATION );
823 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
824 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(toggle_show_handles), desktop );
825 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.nodes", "show_handles", 1 ) );
826 }
828 } // end of sp_node_toolbox_prep()
831 //########################
832 //## Zoom Toolbox ##
833 //########################
835 static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
836 {
837 // no custom GtkAction setup needed
838 } // end of sp_zoom_toolbox_prep()
840 void
841 sp_tool_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
842 {
843 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")));
844 }
847 void
848 sp_aux_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
849 {
850 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")));
851 }
853 void
854 sp_commands_toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop)
855 {
856 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")));
857 }
859 static void
860 toolbox_set_desktop(GtkWidget *toolbox, SPDesktop *desktop, SetupFunction setup_func, UpdateFunction update_func, sigc::connection *conn)
861 {
862 gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop");
863 SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr);
865 if (old_desktop) {
866 GList *children, *iter;
868 children = gtk_container_get_children(GTK_CONTAINER(toolbox));
869 for ( iter = children ; iter ; iter = iter->next ) {
870 gtk_container_remove( GTK_CONTAINER(toolbox), GTK_WIDGET(iter->data) );
871 }
872 g_list_free(children);
873 }
875 g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop);
877 if (desktop) {
878 gtk_widget_set_sensitive(toolbox, TRUE);
879 setup_func(toolbox, desktop);
880 update_func(desktop, desktop->event_context, toolbox);
881 *conn = desktop->connectEventContextChanged
882 (sigc::bind (sigc::ptr_fun(update_func), toolbox));
883 } else {
884 gtk_widget_set_sensitive(toolbox, FALSE);
885 }
887 } // end of toolbox_set_desktop()
890 static void
891 setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
892 {
893 GtkTooltips *tooltips=GTK_TOOLTIPS(g_object_get_data(G_OBJECT(toolbox), "tooltips"));
894 gint shrinkLeft = prefs_get_int_attribute_limited( "toolbox.left", "small", 0, 0, 1 );
895 Inkscape::IconSize toolboxSize = shrinkLeft ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
897 for (int i = 0 ; tools[i].type_name ; i++ ) {
898 GtkWidget *button =
899 sp_toolbox_button_new_from_verb_with_doubleclick( toolbox, toolboxSize,
900 SP_BUTTON_TYPE_TOGGLE,
901 Inkscape::Verb::get(tools[i].verb),
902 Inkscape::Verb::get(tools[i].doubleclick_verb),
903 desktop,
904 tooltips );
906 g_object_set_data( G_OBJECT(toolbox), tools[i].data_name,
907 (gpointer)button );
908 }
909 }
912 static void
913 update_tool_toolbox( SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox )
914 {
915 gchar const *const tname = ( eventcontext
916 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
917 : NULL );
918 for (int i = 0 ; tools[i].type_name ; i++ ) {
919 SPButton *button = SP_BUTTON(g_object_get_data(G_OBJECT(toolbox), tools[i].data_name));
920 sp_button_toggle_set_down(button, tname && !strcmp(tname, tools[i].type_name));
921 }
922 }
924 static void
925 setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
926 {
927 GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH );
928 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
929 GtkUIManager* mgr = gtk_ui_manager_new();
930 GError* errVal = 0;
931 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
932 gtk_ui_manager_add_ui_from_string( mgr, ui_descr, -1, &errVal );
934 std::map<std::string, GtkWidget*> dataHolders;
936 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
937 if ( aux_toolboxes[i].prep_func ) {
938 // converted to GtkActions and UIManager
940 GtkWidget* kludge = gtk_hbox_new( FALSE, 0 );
941 g_object_set_data( G_OBJECT(kludge), "dtw", desktop->canvas);
942 g_object_set_data( G_OBJECT(kludge), "desktop", desktop);
943 dataHolders[aux_toolboxes[i].type_name] = kludge;
944 aux_toolboxes[i].prep_func( desktop, mainActions, G_OBJECT(kludge) );
945 } else {
947 GtkWidget *sub_toolbox = 0;
948 if (aux_toolboxes[i].create_func == NULL)
949 sub_toolbox = sp_empty_toolbox_new(desktop);
950 else {
951 sub_toolbox = aux_toolboxes[i].create_func(desktop);
952 }
954 gtk_size_group_add_widget( grouper, sub_toolbox );
956 gtk_container_add(GTK_CONTAINER(toolbox), sub_toolbox);
957 g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, sub_toolbox);
959 }
960 }
962 // Second pass to create toolbars *after* all GtkActions are created
963 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
964 if ( aux_toolboxes[i].prep_func ) {
965 // converted to GtkActions and UIManager
967 GtkWidget* kludge = dataHolders[aux_toolboxes[i].type_name];
969 GtkWidget* holder = gtk_table_new( 1, 3, FALSE );
970 gtk_table_attach( GTK_TABLE(holder), kludge, 2, 3, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0 );
972 gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name );
973 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp );
974 g_free( tmp );
975 tmp = 0;
977 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
978 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
979 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
980 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) );
983 gtk_table_attach( GTK_TABLE(holder), toolBar, 0, 1, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0 );
985 if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) {
986 Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( NULL, aux_toolboxes[i].swatch_tip );
987 swatch->setDesktop( desktop );
988 swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
989 swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
990 GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
991 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 );
992 }
994 gtk_widget_show_all( holder );
995 sp_set_font_size_smaller( holder );
997 gtk_size_group_add_widget( grouper, holder );
999 gtk_container_add( GTK_CONTAINER(toolbox), holder );
1000 g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder );
1001 }
1002 }
1004 g_object_unref( G_OBJECT(grouper) );
1005 }
1007 static void
1008 update_aux_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1009 {
1010 gchar const *tname = ( eventcontext
1011 ? gtk_type_name(GTK_OBJECT_TYPE(eventcontext))
1012 : NULL );
1013 for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
1014 GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
1015 if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
1016 gtk_widget_show_all(sub_toolbox);
1017 g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
1018 } else {
1019 gtk_widget_hide(sub_toolbox);
1020 }
1021 }
1022 }
1024 static void
1025 setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
1026 {
1027 gchar const * descr =
1028 "<ui>"
1029 " <toolbar name='CommandsToolbar'>"
1030 " <toolitem action='FileNew' />"
1031 " <toolitem action='FileOpen' />"
1032 " <toolitem action='FileSave' />"
1033 " <toolitem action='FilePrint' />"
1034 " <separator />"
1035 " <toolitem action='FileImport' />"
1036 " <toolitem action='FileExport' />"
1037 " <separator />"
1038 " <toolitem action='EditUndo' />"
1039 " <toolitem action='EditRedo' />"
1040 " <separator />"
1041 " <toolitem action='EditCopy' />"
1042 " <toolitem action='EditCut' />"
1043 " <toolitem action='EditPaste' />"
1044 " <separator />"
1045 " <toolitem action='ZoomSelection' />"
1046 " <toolitem action='ZoomDrawing' />"
1047 " <toolitem action='ZoomPage' />"
1048 " <separator />"
1049 " <toolitem action='EditDuplicate' />"
1050 " <toolitem action='EditClone' />"
1051 " <toolitem action='EditUnlinkClone' />"
1052 " <separator />"
1053 " <toolitem action='SelectionGroup' />"
1054 " <toolitem action='SelectionUnGroup' />"
1055 " <separator />"
1056 " <toolitem action='DialogFillStroke' />"
1057 " <toolitem action='DialogText' />"
1058 " <toolitem action='DialogXMLEditor' />"
1059 " <toolitem action='DialogAlignDistribute' />"
1060 " <separator />"
1061 " <toolitem action='DialogPreferences' />"
1062 " <toolitem action='DialogDocumentProperties' />"
1063 " </toolbar>"
1064 "</ui>";
1065 GtkActionGroup* mainActions = create_or_fetch_actions( desktop );
1068 GtkUIManager* mgr = gtk_ui_manager_new();
1069 GError* errVal = 0;
1071 gtk_ui_manager_insert_action_group( mgr, mainActions, 0 );
1072 gtk_ui_manager_add_ui_from_string( mgr, descr, -1, &errVal );
1074 GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, "/ui/CommandsToolbar" );
1075 gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS );
1076 gint shrinkTop = prefs_get_int_attribute_limited( "toolbox", "small", 1, 0, 1 );
1077 Inkscape::IconSize toolboxSize = shrinkTop ? Inkscape::ICON_SIZE_SMALL_TOOLBAR : Inkscape::ICON_SIZE_LARGE_TOOLBAR;
1078 gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), (GtkIconSize)toolboxSize );
1081 gtk_container_add( GTK_CONTAINER(toolbox), toolBar );
1082 }
1084 static void
1085 update_commands_toolbox(SPDesktop *desktop, SPEventContext *eventcontext, GtkWidget *toolbox)
1086 {
1087 }
1089 void show_aux_toolbox(GtkWidget *toolbox_toplevel)
1090 {
1091 gtk_widget_show(toolbox_toplevel);
1092 GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel));
1094 GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows"));
1095 if (!shown_toolbox) {
1096 return;
1097 }
1098 gtk_widget_show(toolbox);
1100 // need to show the spacer, or the padding will be off
1101 GtkWidget *spacer = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "top_spacer"));
1102 gtk_widget_show(spacer);
1104 gtk_widget_show_all(shown_toolbox);
1105 }
1107 void
1108 aux_toolbox_space(GtkWidget *tb, gint space)
1109 {
1110 gtk_box_pack_start(GTK_BOX(tb), gtk_hbox_new(FALSE, 0), FALSE, FALSE, space);
1111 }
1113 static GtkWidget *
1114 sp_empty_toolbox_new(SPDesktop *desktop)
1115 {
1116 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
1117 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
1118 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
1120 gtk_widget_show_all(tbl);
1121 sp_set_font_size_smaller (tbl);
1123 return tbl;
1124 }
1126 // helper UI functions
1128 GtkWidget *
1129 sp_tb_spinbutton(
1130 gchar *label, gchar const *tooltip,
1131 gchar const *path, gchar const *data, gdouble def,
1132 GtkWidget *us,
1133 GtkWidget *tbl,
1134 gboolean altx, gchar const *altx_mark,
1135 gdouble lower, gdouble upper, gdouble step, gdouble page,
1136 void (*callback)(GtkAdjustment *, GtkWidget *),
1137 gdouble climb = 0.1, guint digits = 3, double factor = 1.0)
1138 {
1139 GtkTooltips *tt = gtk_tooltips_new();
1141 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
1143 GtkWidget *l = gtk_label_new(label);
1144 gtk_widget_show(l);
1145 gtk_misc_set_alignment(GTK_MISC(l), 1.0, 0.5);
1146 gtk_container_add(GTK_CONTAINER(hb), l);
1148 GtkObject *a = gtk_adjustment_new(prefs_get_double_attribute(path, data, def) * factor,
1149 lower, upper, step, page, page);
1150 gtk_object_set_data(GTK_OBJECT(tbl), data, a);
1151 if (us)
1152 sp_unit_selector_add_adjustment(SP_UNIT_SELECTOR(us), GTK_ADJUSTMENT(a));
1154 GtkWidget *sb = gtk_spin_button_new(GTK_ADJUSTMENT(a), climb, digits);
1155 gtk_tooltips_set_tip(tt, sb, tooltip, NULL);
1156 if (altx)
1157 gtk_object_set_data(GTK_OBJECT(sb), altx_mark, sb);
1158 gtk_widget_set_size_request(sb,
1159 (upper <= 1.0 || digits == 0)? AUX_SPINBUTTON_WIDTH_SMALL - 10: AUX_SPINBUTTON_WIDTH_SMALL,
1160 AUX_SPINBUTTON_HEIGHT);
1161 gtk_widget_show(sb);
1162 gtk_signal_connect(GTK_OBJECT(sb), "focus-in-event", GTK_SIGNAL_FUNC(spinbutton_focus_in), tbl);
1163 gtk_signal_connect(GTK_OBJECT(sb), "key-press-event", GTK_SIGNAL_FUNC(spinbutton_keypress), tbl);
1164 gtk_container_add(GTK_CONTAINER(hb), sb);
1165 gtk_signal_connect(GTK_OBJECT(a), "value_changed", GTK_SIGNAL_FUNC(callback), tbl);
1167 return hb;
1168 }
1170 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
1171 gchar const *label, gchar const *tooltip,
1172 gchar const *path, gchar const *data, gdouble def,
1173 GtkWidget *focusTarget,
1174 GtkWidget *us,
1175 GObject *dataKludge,
1176 gboolean altx, gchar const *altx_mark,
1177 gdouble lower, gdouble upper, gdouble step, gdouble page,
1178 gchar const** descrLabels, gdouble const* descrValues, guint descrCount,
1179 void (*callback)(GtkAdjustment *, GObject *),
1180 gdouble climb = 0.1, guint digits = 3, double factor = 1.0 )
1181 {
1182 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs_get_double_attribute(path, data, def) * factor,
1183 lower, upper, step, page, page ) );
1184 if (us) {
1185 sp_unit_selector_add_adjustment( SP_UNIT_SELECTOR(us), adj );
1186 }
1188 gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(callback), dataKludge );
1190 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, 0, climb, digits );
1192 if ( (descrCount > 0) && descrLabels && descrValues ) {
1193 ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount );
1194 }
1196 if ( focusTarget ) {
1197 ege_adjustment_action_set_focuswidget( act, focusTarget );
1198 }
1200 if ( altx && altx_mark ) {
1201 g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL );
1202 }
1204 if ( dataKludge ) {
1205 g_object_set_data( dataKludge, data, adj );
1206 }
1208 // Using a cast just to make sure we pass in the right kind of function pointer
1209 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
1211 return act;
1212 }
1215 #define MODE_LABEL_WIDTH 70
1217 //########################
1218 //## Star ##
1219 //########################
1221 static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1222 {
1223 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1225 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1226 // do not remember prefs if this call is initiated by an undo change, because undoing object
1227 // creation sets bogus values to its attributes before it is deleted
1228 prefs_set_int_attribute("tools.shapes.star", "magnitude", (gint)adj->value);
1229 }
1231 // quit if run by the attr_changed listener
1232 if (g_object_get_data( dataKludge, "freeze" )) {
1233 return;
1234 }
1236 // in turn, prevent listener from responding
1237 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1239 bool modmade = false;
1241 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1242 GSList const *items = selection->itemList();
1243 for (; items != NULL; items = items->next) {
1244 if (SP_IS_STAR((SPItem *) items->data)) {
1245 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1246 sp_repr_set_int(repr,"sodipodi:sides",(gint)adj->value);
1247 sp_repr_set_svg_double(repr, "sodipodi:arg2",
1248 (sp_repr_get_double_attribute(repr, "sodipodi:arg1", 0.5)
1249 + M_PI / (gint)adj->value));
1250 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1251 modmade = true;
1252 }
1253 }
1254 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1255 _("Star: Change number of corners"));
1257 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1258 }
1260 static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1261 {
1262 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1264 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1265 prefs_set_double_attribute("tools.shapes.star", "proportion", adj->value);
1266 }
1268 // quit if run by the attr_changed listener
1269 if (g_object_get_data( dataKludge, "freeze" )) {
1270 return;
1271 }
1273 // in turn, prevent listener from responding
1274 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1276 bool modmade = false;
1277 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1278 GSList const *items = selection->itemList();
1279 for (; items != NULL; items = items->next) {
1280 if (SP_IS_STAR((SPItem *) items->data)) {
1281 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1283 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1284 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1285 if (r2 < r1) {
1286 sp_repr_set_svg_double(repr, "sodipodi:r2", r1*adj->value);
1287 } else {
1288 sp_repr_set_svg_double(repr, "sodipodi:r1", r2*adj->value);
1289 }
1291 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1292 modmade = true;
1293 }
1294 }
1296 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1297 _("Star: Change spoke ratio"));
1299 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1300 }
1302 static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *dataKludge )
1303 {
1304 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1305 bool flat = ege_select_one_action_get_active( act ) == 0;
1307 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1308 prefs_set_string_attribute( "tools.shapes.star", "isflatsided",
1309 flat ? "true" : "false" );
1310 }
1312 // quit if run by the attr_changed listener
1313 if (g_object_get_data( dataKludge, "freeze" )) {
1314 return;
1315 }
1317 // in turn, prevent listener from responding
1318 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1320 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1321 GSList const *items = selection->itemList();
1322 GtkAction* prop_action = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1323 bool modmade = false;
1325 if ( prop_action ) {
1326 gtk_action_set_sensitive( prop_action, !flat );
1327 }
1329 for (; items != NULL; items = items->next) {
1330 if (SP_IS_STAR((SPItem *) items->data)) {
1331 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1332 repr->setAttribute("inkscape:flatsided", flat ? "true" : "false" );
1333 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1334 modmade = true;
1335 }
1336 }
1338 if (modmade) {
1339 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1340 flat ? _("Make polygon") : _("Make star"));
1341 }
1343 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1344 }
1346 static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1347 {
1348 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1350 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1351 prefs_set_double_attribute("tools.shapes.star", "rounded", (gdouble) adj->value);
1352 }
1354 // quit if run by the attr_changed listener
1355 if (g_object_get_data( dataKludge, "freeze" )) {
1356 return;
1357 }
1359 // in turn, prevent listener from responding
1360 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1362 bool modmade = false;
1364 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1365 GSList const *items = selection->itemList();
1366 for (; items != NULL; items = items->next) {
1367 if (SP_IS_STAR((SPItem *) items->data)) {
1368 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1369 sp_repr_set_svg_double(repr, "inkscape:rounded", (gdouble) adj->value);
1370 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1371 modmade = true;
1372 }
1373 }
1374 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1375 _("Star: Change rounding"));
1377 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1378 }
1380 static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKludge )
1381 {
1382 SPDesktop *desktop = (SPDesktop *) g_object_get_data( dataKludge, "desktop" );
1384 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1385 prefs_set_double_attribute("tools.shapes.star", "randomized", (gdouble) adj->value);
1386 }
1388 // quit if run by the attr_changed listener
1389 if (g_object_get_data( dataKludge, "freeze" )) {
1390 return;
1391 }
1393 // in turn, prevent listener from responding
1394 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(TRUE) );
1396 bool modmade = false;
1398 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1399 GSList const *items = selection->itemList();
1400 for (; items != NULL; items = items->next) {
1401 if (SP_IS_STAR((SPItem *) items->data)) {
1402 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
1403 sp_repr_set_svg_double(repr, "inkscape:randomized", (gdouble) adj->value);
1404 SP_OBJECT(items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
1405 modmade = true;
1406 }
1407 }
1408 if (modmade) sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_STAR,
1409 _("Star: Change randomization"));
1411 g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) );
1412 }
1415 static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1416 gchar const *old_value, gchar const *new_value,
1417 bool is_interactive, gpointer data)
1418 {
1419 GtkWidget *tbl = GTK_WIDGET(data);
1421 // quit if run by the _changed callbacks
1422 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
1423 return;
1424 }
1426 // in turn, prevent callbacks from responding
1427 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
1429 GtkAdjustment *adj = 0;
1431 if (!strcmp(name, "inkscape:randomized")) {
1432 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "randomized") );
1433 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:randomized", 0.0));
1434 } else if (!strcmp(name, "inkscape:rounded")) {
1435 adj = GTK_ADJUSTMENT( gtk_object_get_data(GTK_OBJECT(tbl), "rounded") );
1436 gtk_adjustment_set_value(adj, sp_repr_get_double_attribute(repr, "inkscape:rounded", 0.0));
1437 } else if (!strcmp(name, "inkscape:flatsided")) {
1438 GtkAction* prop_action = GTK_ACTION( g_object_get_data(G_OBJECT(tbl), "prop_action") );
1439 char const *flatsides = repr->attribute("inkscape:flatsided");
1440 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
1441 if ( flatsides && !strcmp(flatsides,"false") ) {
1442 ege_select_one_action_set_active( flat_action, 1 );
1443 gtk_action_set_sensitive( prop_action, TRUE );
1444 } else {
1445 ege_select_one_action_set_active( flat_action, 0 );
1446 gtk_action_set_sensitive( prop_action, FALSE );
1447 }
1448 } else if (!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) {
1449 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "proportion");
1450 gdouble r1 = sp_repr_get_double_attribute(repr, "sodipodi:r1", 1.0);
1451 gdouble r2 = sp_repr_get_double_attribute(repr, "sodipodi:r2", 1.0);
1452 if (r2 < r1) {
1453 gtk_adjustment_set_value(adj, r2/r1);
1454 } else {
1455 gtk_adjustment_set_value(adj, r1/r2);
1456 }
1457 } else if (!strcmp(name, "sodipodi:sides")) {
1458 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "magnitude");
1459 gtk_adjustment_set_value(adj, sp_repr_get_int_attribute(repr, "sodipodi:sides", 0));
1460 }
1462 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
1463 }
1466 static Inkscape::XML::NodeEventVector star_tb_repr_events =
1467 {
1468 NULL, /* child_added */
1469 NULL, /* child_removed */
1470 star_tb_event_attr_changed,
1471 NULL, /* content_changed */
1472 NULL /* order_changed */
1473 };
1476 /**
1477 * \param selection Should not be NULL.
1478 */
1479 static void
1480 sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1481 {
1482 int n_selected = 0;
1483 Inkscape::XML::Node *repr = NULL;
1484 Inkscape::XML::Node *oldrepr = NULL;
1486 for (GSList const *items = selection->itemList();
1487 items != NULL;
1488 items = items->next)
1489 {
1490 if (SP_IS_STAR((SPItem *) items->data)) {
1491 n_selected++;
1492 repr = SP_OBJECT_REPR((SPItem *) items->data);
1493 }
1494 }
1496 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1498 if (n_selected == 0) {
1499 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1500 } else if (n_selected == 1) {
1501 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1503 oldrepr = (Inkscape::XML::Node *) g_object_get_data( tbl, "repr" );
1504 if (oldrepr) { // remove old listener
1505 sp_repr_remove_listener_by_data(oldrepr, tbl);
1506 Inkscape::GC::release(oldrepr);
1507 oldrepr = 0;
1508 g_object_set_data( tbl, "repr", NULL );
1509 }
1511 if (repr) {
1512 g_object_set_data( tbl, "repr", repr );
1513 Inkscape::GC::anchor(repr);
1514 sp_repr_add_listener(repr, &star_tb_repr_events, tbl);
1515 sp_repr_synthesize_events(repr, &star_tb_repr_events, tbl);
1516 }
1517 } else {
1518 // FIXME: implement averaging of all parameters for multiple selected stars
1519 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1520 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Change:</b>"));
1521 }
1522 }
1525 static void sp_stb_defaults( GtkWidget *widget, GObject *dataKludge )
1526 {
1527 // FIXME: in this and all other _default functions, set some flag telling the value_changed
1528 // callbacks to lump all the changes for all selected objects in one undo step
1530 GtkAdjustment *adj = 0;
1532 // fixme: make settable in prefs!
1533 gint mag = 5;
1534 gdouble prop = 0.5;
1535 gboolean flat = FALSE;
1536 gdouble randomized = 0;
1537 gdouble rounded = 0;
1539 EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( dataKludge, "flat_action" ) );
1540 ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
1542 GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
1543 gtk_action_set_sensitive( sb2, !flat );
1545 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
1546 gtk_adjustment_set_value(adj, mag);
1547 gtk_adjustment_value_changed(adj);
1549 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "proportion" ) );
1550 gtk_adjustment_set_value(adj, prop);
1551 gtk_adjustment_value_changed(adj);
1553 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "rounded" ) );
1554 gtk_adjustment_set_value(adj, rounded);
1555 gtk_adjustment_value_changed(adj);
1557 adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "randomized" ) );
1558 gtk_adjustment_set_value(adj, randomized);
1559 gtk_adjustment_value_changed(adj);
1560 }
1563 void
1564 sp_toolbox_add_label(GtkWidget *tbl, gchar const *title, bool wide)
1565 {
1566 GtkWidget *boxl = gtk_hbox_new(FALSE, 0);
1567 if (wide) gtk_widget_set_size_request(boxl, MODE_LABEL_WIDTH, -1);
1568 GtkWidget *l = gtk_label_new(NULL);
1569 gtk_label_set_markup(GTK_LABEL(l), title);
1570 gtk_box_pack_end(GTK_BOX(boxl), l, FALSE, FALSE, 0);
1571 gtk_box_pack_start(GTK_BOX(tbl), boxl, FALSE, FALSE, 0);
1572 gtk_object_set_data(GTK_OBJECT(tbl), "mode_label", l);
1573 }
1576 static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1577 {
1578 {
1579 EgeOutputAction* act = ege_output_action_new( "StarStateAction", _("<b>New:</b>"), "", 0 );
1580 ege_output_action_set_use_markup( act, TRUE );
1581 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1582 g_object_set_data( holder, "mode_action", act );
1583 }
1585 {
1586 //EgeAdjustmentAction* calligraphy_angle = 0;
1587 EgeAdjustmentAction* eact = 0;
1588 gchar const *flatsidedstr = prefs_get_string_attribute( "tools.shapes.star", "isflatsided" );
1589 bool isFlatSided = flatsidedstr ? (strcmp(flatsidedstr, "false") != 0) : true;
1591 /* Flatsided checkbox */
1592 {
1593 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
1595 GtkTreeIter iter;
1596 gtk_list_store_append( model, &iter );
1597 gtk_list_store_set( model, &iter,
1598 0, _("Polygon"),
1599 1, _("Regular polygon (with one handle) instead of a star"),
1600 2, "star_flat",
1601 -1 );
1603 gtk_list_store_append( model, &iter );
1604 gtk_list_store_set( model, &iter,
1605 0, _("Star"),
1606 1, _("Star instead of a regular polygon (with one handle)"),
1607 2, "star_angled",
1608 -1 );
1610 EgeSelectOneAction* act = ege_select_one_action_new( "FlatAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
1611 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
1612 g_object_set_data( holder, "flat_action", act );
1614 ege_select_one_action_set_appearance( act, "full" );
1615 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
1616 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
1617 ege_select_one_action_set_icon_column( act, 2 );
1618 ege_select_one_action_set_tooltip_column( act, 1 );
1620 ege_select_one_action_set_active( act, isFlatSided ? 0 : 1 );
1621 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_stb_sides_flat_state_changed), holder);
1622 }
1624 /* Magnitude */
1625 //gchar const* labels[] = {_("tri (default)"), _("quad"), _("pent")};
1626 //gdouble values[] = {3, 4, 5};
1627 eact = create_adjustment_action( "MagnitudeAction",
1628 _("Corners:"), _("Number of corners of a polygon or star"),
1629 "tools.shapes.star", "magnitude", 3,
1630 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1631 3, 1024, 1, 5,
1632 0, 0, 0, // labels, values, G_N_ELEMENTS(labels),
1633 sp_stb_magnitude_value_changed,
1634 1.0, 0 );
1635 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1636 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1638 /* Spoke ratio */
1639 //gchar const* labels2[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1640 //gdouble values2[] = {-90, 0, 30, 90};
1641 eact = create_adjustment_action( "SpokeAction",
1642 _("Spoke ratio:"),
1643 // TRANSLATORS: Tip radius of a star is the distance from the center to the farthest handle.
1644 // Base radius is the same for the closest handle.
1645 _("Base radius to tip radius ratio"),
1646 "tools.shapes.star", "proportion", 0.5,
1647 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1648 0.01, 1.0, 0.01, 0.1,
1649 0, 0, 0, // labels2, values2, G_N_ELEMENTS(labels2),
1650 sp_stb_proportion_value_changed );
1651 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1652 g_object_set_data( holder, "prop_action", eact );
1654 if ( !isFlatSided ) {
1655 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1656 } else {
1657 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1658 }
1660 /* Roundedness */
1661 //gchar const* labels3[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1662 //gdouble values3[] = {-90, 0, 30, 90};
1663 eact = create_adjustment_action( "RoundednessAction",
1664 _("Rounded:"), _("How much rounded are the corners (0 for sharp)"),
1665 "tools.shapes.star", "rounded", 0.0,
1666 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1667 -100.0, 100.0, 0.01, 0.1,
1668 0, 0, 0, // labels3, values3, G_N_ELEMENTS(labels3),
1669 sp_stb_rounded_value_changed );
1670 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1671 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1673 /* Randomization */
1674 //gchar const* labels4[] = {_("(left edge up)"), _("(horizontal)"), _("(default)"), _("(right edge up)")};
1675 //gdouble values4[] = {-90, 0, 30, 90};
1676 eact = create_adjustment_action( "RandomizationAction",
1677 _("Randomized:"), _("Scatter randomly the corners and angles"),
1678 "tools.shapes.star", "randomized", 0.0,
1679 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
1680 -10.0, 10.0, 0.001, 0.01,
1681 0, 0, 0, // labels4, values4, G_N_ELEMENTS(labels4),
1682 sp_stb_randomized_value_changed, 0.1, 3 );
1683 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1684 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
1685 }
1687 {
1688 /* Reset */
1689 {
1690 GtkAction* act = gtk_action_new( "StarResetAction",
1691 _("Defaults"),
1692 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
1693 GTK_STOCK_CLEAR );
1694 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_stb_defaults), holder );
1695 gtk_action_group_add_action( mainActions, act );
1696 gtk_action_set_sensitive( act, TRUE );
1697 }
1698 }
1700 sigc::connection *connection = new sigc::connection(
1701 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_star_toolbox_selection_changed), (GObject *)holder))
1702 );
1703 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
1704 }
1707 //########################
1708 //## Rect ##
1709 //########################
1711 static void sp_rtb_sensitivize( GObject *tbl )
1712 {
1713 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data(tbl, "rx") );
1714 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data(tbl, "ry") );
1715 GtkAction* not_rounded = GTK_ACTION( g_object_get_data(tbl, "not_rounded") );
1717 if (adj1->value == 0 && adj2->value == 0 && g_object_get_data(tbl, "single")) { // only for a single selected rect (for now)
1718 gtk_action_set_sensitive( not_rounded, FALSE );
1719 } else {
1720 gtk_action_set_sensitive( not_rounded, TRUE );
1721 }
1722 }
1725 static void
1726 sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name,
1727 void (*setter)(SPRect *, gdouble))
1728 {
1729 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
1731 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
1732 SPUnit const *unit = tracker->getActiveUnit();
1734 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
1735 prefs_set_double_attribute("tools.shapes.rect", value_name, sp_units_get_pixels(adj->value, *unit));
1736 }
1738 // quit if run by the attr_changed listener
1739 if (g_object_get_data( tbl, "freeze" )) {
1740 return;
1741 }
1743 // in turn, prevent listener from responding
1744 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE));
1746 bool modmade = false;
1747 Inkscape::Selection *selection = sp_desktop_selection(desktop);
1748 for (GSList const *items = selection->itemList(); items != NULL; items = items->next) {
1749 if (SP_IS_RECT(items->data)) {
1750 if (adj->value != 0) {
1751 setter(SP_RECT(items->data), sp_units_get_pixels(adj->value, *unit));
1752 } else {
1753 SP_OBJECT_REPR(items->data)->setAttribute(value_name, NULL);
1754 }
1755 modmade = true;
1756 }
1757 }
1759 sp_rtb_sensitivize( tbl );
1761 if (modmade) {
1762 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_RECT,
1763 _("Change rectangle"));
1764 }
1766 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1767 }
1769 static void
1770 sp_rtb_rx_value_changed(GtkAdjustment *adj, GObject *tbl)
1771 {
1772 sp_rtb_value_changed(adj, tbl, "rx", sp_rect_set_visible_rx);
1773 }
1775 static void
1776 sp_rtb_ry_value_changed(GtkAdjustment *adj, GObject *tbl)
1777 {
1778 sp_rtb_value_changed(adj, tbl, "ry", sp_rect_set_visible_ry);
1779 }
1781 static void
1782 sp_rtb_width_value_changed(GtkAdjustment *adj, GObject *tbl)
1783 {
1784 sp_rtb_value_changed(adj, tbl, "width", sp_rect_set_visible_width);
1785 }
1787 static void
1788 sp_rtb_height_value_changed(GtkAdjustment *adj, GObject *tbl)
1789 {
1790 sp_rtb_value_changed(adj, tbl, "height", sp_rect_set_visible_height);
1791 }
1795 static void
1796 sp_rtb_defaults( GtkWidget *widget, GObject *obj)
1797 {
1798 GtkAdjustment *adj = 0;
1800 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "rx") );
1801 gtk_adjustment_set_value(adj, 0.0);
1802 // this is necessary if the previous value was 0, but we still need to run the callback to change all selected objects
1803 gtk_adjustment_value_changed(adj);
1805 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "ry") );
1806 gtk_adjustment_set_value(adj, 0.0);
1807 gtk_adjustment_value_changed(adj);
1809 sp_rtb_sensitivize( obj );
1810 }
1812 static void rect_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
1813 gchar const *old_value, gchar const *new_value,
1814 bool is_interactive, gpointer data)
1815 {
1816 GObject *tbl = G_OBJECT(data);
1818 // quit if run by the _changed callbacks
1819 if (g_object_get_data( tbl, "freeze" )) {
1820 return;
1821 }
1823 // in turn, prevent callbacks from responding
1824 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
1826 UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
1827 SPUnit const *unit = tracker->getActiveUnit();
1829 gpointer item = g_object_get_data( tbl, "item" );
1830 if (item && SP_IS_RECT(item)) {
1831 {
1832 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "rx" ) );
1833 gdouble rx = sp_rect_get_visible_rx(SP_RECT(item));
1834 gtk_adjustment_set_value(adj, sp_pixels_get_units(rx, *unit));
1835 }
1837 {
1838 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "ry" ) );
1839 gdouble ry = sp_rect_get_visible_ry(SP_RECT(item));
1840 gtk_adjustment_set_value(adj, sp_pixels_get_units(ry, *unit));
1841 }
1843 {
1844 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
1845 gdouble width = sp_rect_get_visible_width (SP_RECT(item));
1846 gtk_adjustment_set_value(adj, sp_pixels_get_units(width, *unit));
1847 }
1849 {
1850 GtkAdjustment *adj = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
1851 gdouble height = sp_rect_get_visible_height (SP_RECT(item));
1852 gtk_adjustment_set_value(adj, sp_pixels_get_units(height, *unit));
1853 }
1854 }
1856 sp_rtb_sensitivize( tbl );
1858 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
1859 }
1862 static Inkscape::XML::NodeEventVector rect_tb_repr_events = {
1863 NULL, /* child_added */
1864 NULL, /* child_removed */
1865 rect_tb_event_attr_changed,
1866 NULL, /* content_changed */
1867 NULL /* order_changed */
1868 };
1870 /**
1871 * \param selection should not be NULL.
1872 */
1873 static void
1874 sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
1875 {
1876 int n_selected = 0;
1877 Inkscape::XML::Node *repr = NULL;
1878 SPItem *item = NULL;
1879 Inkscape::XML::Node *oldrepr = NULL;
1881 for (GSList const *items = selection->itemList();
1882 items != NULL;
1883 items = items->next) {
1884 if (SP_IS_RECT((SPItem *) items->data)) {
1885 n_selected++;
1886 item = (SPItem *) items->data;
1887 repr = SP_OBJECT_REPR(item);
1888 }
1889 }
1891 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
1893 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
1895 if (n_selected == 0) {
1896 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
1898 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1899 gtk_action_set_sensitive(w, FALSE);
1900 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1901 gtk_action_set_sensitive(h, FALSE);
1903 } else if (n_selected == 1) {
1904 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1905 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
1907 GtkAction* w = GTK_ACTION( g_object_get_data( tbl, "width_action" ) );
1908 gtk_action_set_sensitive(w, TRUE);
1909 GtkAction* h = GTK_ACTION( g_object_get_data( tbl, "height_action" ) );
1910 gtk_action_set_sensitive(h, TRUE);
1912 oldrepr = (Inkscape::XML::Node *) g_object_get_data( tbl, "repr" );
1913 if (oldrepr) { // remove old listener
1914 sp_repr_remove_listener_by_data(oldrepr, tbl);
1915 Inkscape::GC::release(oldrepr);
1916 oldrepr = 0;
1917 g_object_set_data( tbl, "repr", NULL );
1918 g_object_set_data( tbl, "item", NULL );
1919 }
1920 if (repr) {
1921 g_object_set_data( tbl, "repr", repr );
1922 g_object_set_data( tbl, "item", item );
1923 Inkscape::GC::anchor(repr);
1924 sp_repr_add_listener(repr, &rect_tb_repr_events, tbl);
1925 sp_repr_synthesize_events(repr, &rect_tb_repr_events, tbl);
1926 }
1927 } else {
1928 // FIXME: implement averaging of all parameters for multiple selected
1929 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
1930 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
1931 sp_rtb_sensitivize( tbl );
1932 }
1933 }
1936 static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
1937 {
1938 EgeAdjustmentAction* eact = 0;
1940 {
1941 EgeOutputAction* act = ege_output_action_new( "RectStateAction", _("<b>New:</b>"), "", 0 );
1942 ege_output_action_set_use_markup( act, TRUE );
1943 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
1944 g_object_set_data( holder, "mode_action", act );
1945 }
1947 // rx/ry units menu: create
1948 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
1949 //tracker->addUnit( SP_UNIT_PERCENT, 0 );
1950 // fixme: add % meaning per cent of the width/height
1951 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
1952 g_object_set_data( holder, "tracker", tracker );
1954 /* W */
1955 {
1956 eact = create_adjustment_action( "RectWidthAction",
1957 _("W:"), _("Width of rectangle"),
1958 "tools.shapes.rect", "width", 0,
1959 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-rect",
1960 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1961 0, 0, 0,
1962 sp_rtb_width_value_changed );
1963 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1964 g_object_set_data( holder, "width_action", eact );
1965 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1966 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1967 }
1969 /* H */
1970 {
1971 eact = create_adjustment_action( "RectHeightAction",
1972 _("H:"), _("Height of rectangle"),
1973 "tools.shapes.rect", "height", 0,
1974 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1975 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1976 0, 0, 0,
1977 sp_rtb_height_value_changed );
1978 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1979 g_object_set_data( holder, "height_action", eact );
1980 gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
1981 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1982 }
1984 /* rx */
1985 {
1986 eact = create_adjustment_action( "RadiusXAction",
1987 _("Rx:"), _("Horizontal radius of rounded corners"),
1988 "tools.shapes.rect", "rx", 0,
1989 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
1990 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
1991 0, 0, 0,
1992 sp_rtb_rx_value_changed);
1993 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
1994 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
1995 }
1997 /* ry */
1998 {
1999 eact = create_adjustment_action( "RadiusYAction",
2000 _("Ry:"), _("Vertical radius of rounded corners"),
2001 "tools.shapes.rect", "ry", 0,
2002 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2003 0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
2004 0, 0, 0,
2005 sp_rtb_ry_value_changed);
2006 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
2007 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2008 }
2010 // add the units menu
2011 {
2012 GtkAction* act = tracker->createAction( "RectUnitsAction", _("Units"), _("") );
2013 gtk_action_group_add_action( mainActions, act );
2014 }
2016 /* Reset */
2017 {
2018 InkAction* inky = ink_action_new( "RectResetAction",
2019 _("Not rounded"),
2020 _("Make corners sharp"),
2021 "squared_corner",
2022 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2023 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_rtb_defaults), holder );
2024 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2025 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2026 g_object_set_data( holder, "not_rounded", inky );
2027 }
2029 g_object_set_data( holder, "single", GINT_TO_POINTER(TRUE) );
2030 sp_rtb_sensitivize( holder );
2032 sigc::connection *connection = new sigc::connection(
2033 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_rect_toolbox_selection_changed), (GObject *)holder))
2034 );
2035 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2036 }
2038 //########################
2039 //## Spiral ##
2040 //########################
2042 static void
2043 sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name)
2044 {
2045 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2047 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2048 prefs_set_double_attribute("tools.shapes.spiral", value_name, adj->value);
2049 }
2051 // quit if run by the attr_changed listener
2052 if (g_object_get_data( tbl, "freeze" )) {
2053 return;
2054 }
2056 // in turn, prevent listener from responding
2057 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2059 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2061 bool modmade = false;
2062 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2063 items != NULL;
2064 items = items->next)
2065 {
2066 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2067 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2068 sp_repr_set_svg_double( repr, namespaced_name, adj->value );
2069 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2070 modmade = true;
2071 }
2072 }
2074 g_free(namespaced_name);
2076 if (modmade) {
2077 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_SPIRAL,
2078 _("Change spiral"));
2079 }
2081 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2082 }
2084 static void
2085 sp_spl_tb_revolution_value_changed(GtkAdjustment *adj, GObject *tbl)
2086 {
2087 sp_spl_tb_value_changed(adj, tbl, "revolution");
2088 }
2090 static void
2091 sp_spl_tb_expansion_value_changed(GtkAdjustment *adj, GObject *tbl)
2092 {
2093 sp_spl_tb_value_changed(adj, tbl, "expansion");
2094 }
2096 static void
2097 sp_spl_tb_t0_value_changed(GtkAdjustment *adj, GObject *tbl)
2098 {
2099 sp_spl_tb_value_changed(adj, tbl, "t0");
2100 }
2102 static void
2103 sp_spl_tb_defaults(GtkWidget *widget, GtkObject *obj)
2104 {
2105 GtkWidget *tbl = GTK_WIDGET(obj);
2107 GtkAdjustment *adj;
2109 // fixme: make settable
2110 gdouble rev = 5;
2111 gdouble exp = 1.0;
2112 gdouble t0 = 0.0;
2114 adj = (GtkAdjustment*)gtk_object_get_data(obj, "revolution");
2115 gtk_adjustment_set_value(adj, rev);
2116 gtk_adjustment_value_changed(adj);
2118 adj = (GtkAdjustment*)gtk_object_get_data(obj, "expansion");
2119 gtk_adjustment_set_value(adj, exp);
2120 gtk_adjustment_value_changed(adj);
2122 adj = (GtkAdjustment*)gtk_object_get_data(obj, "t0");
2123 gtk_adjustment_set_value(adj, t0);
2124 gtk_adjustment_value_changed(adj);
2126 spinbutton_defocus(GTK_OBJECT(tbl));
2127 }
2130 static void spiral_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2131 gchar const *old_value, gchar const *new_value,
2132 bool is_interactive, gpointer data)
2133 {
2134 GtkWidget *tbl = GTK_WIDGET(data);
2136 // quit if run by the _changed callbacks
2137 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
2138 return;
2139 }
2141 // in turn, prevent callbacks from responding
2142 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
2144 GtkAdjustment *adj;
2145 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "revolution");
2146 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:revolution", 3.0)));
2148 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "expansion");
2149 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:expansion", 1.0)));
2151 adj = (GtkAdjustment*)gtk_object_get_data(GTK_OBJECT(tbl), "t0");
2152 gtk_adjustment_set_value(adj, (sp_repr_get_double_attribute(repr, "sodipodi:t0", 0.0)));
2154 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
2155 }
2158 static Inkscape::XML::NodeEventVector spiral_tb_repr_events = {
2159 NULL, /* child_added */
2160 NULL, /* child_removed */
2161 spiral_tb_event_attr_changed,
2162 NULL, /* content_changed */
2163 NULL /* order_changed */
2164 };
2166 static void
2167 sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2168 {
2169 int n_selected = 0;
2170 Inkscape::XML::Node *repr = NULL;
2171 Inkscape::XML::Node *oldrepr = NULL;
2173 for (GSList const *items = selection->itemList();
2174 items != NULL;
2175 items = items->next)
2176 {
2177 if (SP_IS_SPIRAL((SPItem *) items->data)) {
2178 n_selected++;
2179 repr = SP_OBJECT_REPR((SPItem *) items->data);
2180 }
2181 }
2183 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2185 if (n_selected == 0) {
2186 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2187 } else if (n_selected == 1) {
2188 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2190 oldrepr = (Inkscape::XML::Node *) g_object_get_data( tbl, "repr" );
2191 if (oldrepr) { // remove old listener
2192 sp_repr_remove_listener_by_data(oldrepr, tbl);
2193 Inkscape::GC::release(oldrepr);
2194 oldrepr = 0;
2195 g_object_set_data( tbl, "repr", NULL );
2196 }
2198 if (repr) {
2199 g_object_set_data( tbl, "repr", repr );
2200 Inkscape::GC::anchor(repr);
2201 sp_repr_add_listener(repr, &spiral_tb_repr_events, tbl);
2202 sp_repr_synthesize_events(repr, &spiral_tb_repr_events, tbl);
2203 }
2204 } else {
2205 // FIXME: implement averaging of all parameters for multiple selected
2206 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2207 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2208 }
2209 }
2212 static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2213 {
2214 EgeAdjustmentAction* eact = 0;
2216 {
2217 EgeOutputAction* act = ege_output_action_new( "SpiralStateAction", _("<b>New:</b>"), "", 0 );
2218 ege_output_action_set_use_markup( act, TRUE );
2219 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2220 g_object_set_data( holder, "mode_action", act );
2221 }
2223 /* Revolution */
2224 {
2225 eact = create_adjustment_action( "SpiralRevolutionAction",
2226 _("Turns:"), _("Number of revolutions"),
2227 "tools.shapes.spiral", "revolution", 3.0,
2228 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spiral",
2229 0.01, 1024.0, 0.1, 1.0,
2230 0, 0, 0,
2231 sp_spl_tb_revolution_value_changed, 1, 2);
2232 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2233 }
2235 /* Expansion */
2236 {
2237 eact = create_adjustment_action( "SpiralExpansionAction",
2238 _("Divergence:"), _("How much denser/sparser are outer revolutions; 1 = uniform"),
2239 "tools.shapes.spiral", "expansion", 1.0,
2240 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2241 0.0, 1000.0, 0.01, 1.0,
2242 0, 0, 0,
2243 sp_spl_tb_expansion_value_changed);
2244 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2245 }
2247 /* T0 */
2248 {
2249 eact = create_adjustment_action( "SpiralT0Action",
2250 _("Inner radius:"), _("Radius of the innermost revolution (relative to the spiral size)"),
2251 "tools.shapes.spiral", "t0", 0.0,
2252 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2253 0.0, 0.999, 0.01, 1.0,
2254 0, 0, 0,
2255 sp_spl_tb_t0_value_changed);
2256 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2257 }
2259 /* Reset */
2260 {
2261 InkAction* inky = ink_action_new( "SpiralResetAction",
2262 _("Defaults"),
2263 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2264 GTK_STOCK_CLEAR,
2265 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2266 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_spl_tb_defaults), holder );
2267 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2268 }
2271 sigc::connection *connection = new sigc::connection(
2272 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_spiral_toolbox_selection_changed), (GObject *)holder))
2273 );
2274 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2275 }
2277 //########################
2278 //## Pen/Pencil ##
2279 //########################
2282 static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2283 {
2284 // Put stuff here
2285 }
2287 static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2288 {
2289 // Put stuff here
2290 }
2293 //########################
2294 //## Calligraphy ##
2295 //########################
2297 static void sp_ddc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
2298 {
2299 prefs_set_double_attribute( "tools.calligraphic", "mass", adj->value );
2300 }
2302 static void sp_ddc_wiggle_value_changed( GtkAdjustment *adj, GObject* tbl )
2303 {
2304 prefs_set_double_attribute( "tools.calligraphic", "wiggle", adj->value );
2305 }
2307 static void sp_ddc_angle_value_changed( GtkAdjustment *adj, GObject* tbl )
2308 {
2309 prefs_set_double_attribute( "tools.calligraphic", "angle", adj->value );
2310 }
2312 static void sp_ddc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
2313 {
2314 prefs_set_double_attribute( "tools.calligraphic", "width", adj->value * 0.01 );
2315 }
2317 static void sp_ddc_velthin_value_changed( GtkAdjustment *adj, GObject* tbl )
2318 {
2319 prefs_set_double_attribute("tools.calligraphic", "thinning", adj->value);
2320 }
2322 static void sp_ddc_flatness_value_changed( GtkAdjustment *adj, GObject* tbl )
2323 {
2324 prefs_set_double_attribute( "tools.calligraphic", "flatness", adj->value );
2325 }
2327 static void sp_ddc_tremor_value_changed( GtkAdjustment *adj, GObject* tbl )
2328 {
2329 prefs_set_double_attribute( "tools.calligraphic", "tremor", adj->value );
2330 }
2332 static void sp_ddc_cap_rounding_value_changed( GtkAdjustment *adj, GObject* tbl )
2333 {
2334 prefs_set_double_attribute( "tools.calligraphic", "cap_rounding", adj->value );
2335 }
2337 static void sp_ddc_pressure_state_changed( GtkToggleAction *act, gpointer data )
2338 {
2339 prefs_set_int_attribute( "tools.calligraphic", "usepressure", gtk_toggle_action_get_active( act ) ? 1 : 0);
2340 }
2342 static void sp_ddc_trace_background_changed( GtkToggleAction *act, gpointer data )
2343 {
2344 prefs_set_int_attribute( "tools.calligraphic", "tracebackground", gtk_toggle_action_get_active( act ) ? 1 : 0);
2345 }
2347 static void sp_ddc_tilt_state_changed( GtkToggleAction *act, GtkAction *calligraphy_angle )
2348 {
2349 prefs_set_int_attribute( "tools.calligraphic", "usetilt", gtk_toggle_action_get_active( act ) ? 1 : 0 );
2351 gtk_action_set_sensitive( calligraphy_angle, !gtk_toggle_action_get_active( act ) );
2352 }
2354 static void sp_ddc_defaults(GtkWidget *, GObject *dataKludge)
2355 {
2356 // FIXME: make defaults settable via Inkscape Options
2357 struct KeyValue {
2358 char const *key;
2359 double value;
2360 } const key_values[] = {
2361 {"mass", 0.02},
2362 {"wiggle", 0.0},
2363 {"angle", 30.0},
2364 {"width", 15},
2365 {"thinning", 0.1},
2366 {"tremor", 0.0},
2367 {"flatness", 0.9},
2368 {"cap_rounding", 0.0}
2369 };
2371 for (unsigned i = 0; i < G_N_ELEMENTS(key_values); ++i) {
2372 KeyValue const &kv = key_values[i];
2373 GtkAdjustment* adj = static_cast<GtkAdjustment *>(g_object_get_data(dataKludge, kv.key));
2374 if ( adj ) {
2375 gtk_adjustment_set_value(adj, kv.value);
2376 }
2377 }
2378 }
2381 static void sp_calligraphy_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2382 {
2383 {
2384 EgeAdjustmentAction* calligraphy_angle = 0;
2386 {
2387 /* Width */
2388 gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
2389 gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
2390 EgeAdjustmentAction *eact = create_adjustment_action( "CalligraphyWidthAction",
2391 _("Width:"), _("The width of the calligraphic pen (relative to the visible canvas area)"),
2392 "tools.calligraphic", "width", 15,
2393 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-calligraphy",
2394 1, 100, 1.0, 10.0,
2395 labels, values, G_N_ELEMENTS(labels),
2396 sp_ddc_width_value_changed, 0.01, 0, 100 );
2397 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2398 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2399 }
2401 {
2402 /* Thinning */
2403 gchar const* labels[] = {_("(speed blows up stroke)"), 0, 0, _("(slight widening)"), _("(constant width)"), _("(slight thinning, default)"), 0, 0, _("(speed deflates stroke)")};
2404 gdouble values[] = {-1, -0.4, -0.2, -0.1, 0, 0.1, 0.2, 0.4, 1};
2405 EgeAdjustmentAction* eact = create_adjustment_action( "ThinningAction",
2406 _("Thinning:"), _("How much velocity thins the stroke (> 0 makes fast strokes thinner, < 0 makes them broader, 0 makes width independent of velocity)"),
2407 "tools.calligraphic", "thinning", 0.1,
2408 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2409 -1.0, 1.0, 0.01, 0.1,
2410 labels, values, G_N_ELEMENTS(labels),
2411 sp_ddc_velthin_value_changed, 0.01, 2);
2412 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2413 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2414 }
2416 {
2417 /* Angle */
2418 gchar const* labels[] = {_("(left edge up)"), 0, 0, _("(horizontal)"), _("(default)"), 0, _("(right edge up)")};
2419 gdouble values[] = {-90, -60, -30, 0, 30, 60, 90};
2420 EgeAdjustmentAction* eact = create_adjustment_action( "AngleAction",
2421 _("Angle:"), _("The angle of the pen's nib (in degrees; 0 = horizontal; has no effect if fixation = 0)"),
2422 "tools.calligraphic", "angle", 30,
2423 GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "calligraphy-angle",
2424 -90.0, 90.0, 1.0, 10.0,
2425 labels, values, G_N_ELEMENTS(labels),
2426 sp_ddc_angle_value_changed, 1, 0 );
2427 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2428 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2429 calligraphy_angle = eact;
2430 }
2432 {
2433 /* Fixation */
2434 gchar const* labels[] = {_("(perpendicular to stroke, \"brush\")"), 0, 0, 0, _("(almost fixed, default)"), _("(fixed by Angle, \"pen\")")};
2435 gdouble values[] = {0, 0.2, 0.4, 0.6, 0.9, 1.0};
2436 EgeAdjustmentAction* eact = create_adjustment_action( "FixationAction",
2437 _("Fixation:"), _("Angle behavior (0 = nib always perpendicular to stroke direction, 1 = fixed angle)"),
2438 "tools.calligraphic", "flatness", 0.9,
2439 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2440 0.0, 1.0, 0.01, 0.1,
2441 labels, values, G_N_ELEMENTS(labels),
2442 sp_ddc_flatness_value_changed, 0.01, 2 );
2443 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2444 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2445 }
2447 {
2448 /* Cap Rounding */
2449 gchar const* labels[] = {_("(blunt caps, default)"), _("(slightly bulging)"), 0, 0, _("(approximately round)"), _("(long protruding caps)")};
2450 gdouble values[] = {0, 0.3, 0.5, 1.0, 1.4, 5.0};
2451 // TRANSLATORS: "cap" means "end" (both start and finish) here
2452 EgeAdjustmentAction* eact = create_adjustment_action( "CapRoundingAction",
2453 _("Caps:"), _("Increase to make caps at the ends of strokes protrude more (0 = no caps, 1 = round caps)"),
2454 "tools.calligraphic", "cap_rounding", 0.0,
2455 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2456 0.0, 5.0, 0.01, 0.1,
2457 labels, values, G_N_ELEMENTS(labels),
2458 sp_ddc_cap_rounding_value_changed, 0.01, 2 );
2459 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2460 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2461 }
2463 {
2464 /* Tremor */
2465 gchar const* labels[] = {_("(smooth line)"), _("(slight tremor)"), _("(noticeable tremor)"), 0, 0, _("(maximum tremor)")};
2466 gdouble values[] = {0, 0.1, 0.2, 0.4, 0.6, 1.0};
2467 EgeAdjustmentAction* eact = create_adjustment_action( "TremorAction",
2468 _("Tremor:"), _("Increase to make strokes rugged and trembling"),
2469 "tools.calligraphic", "tremor", 0.0,
2470 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2471 0.0, 1.0, 0.01, 0.1,
2472 labels, values, G_N_ELEMENTS(labels),
2473 sp_ddc_tremor_value_changed, 0.01, 2 );
2475 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2476 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2477 }
2479 {
2480 /* Wiggle */
2481 gchar const* labels[] = {_("(no wiggle)"), _("(slight deviation)"), 0, 0, _("(wild waves and curls)")};
2482 gdouble values[] = {0, 0.2, 0.4, 0.6, 1.0};
2483 EgeAdjustmentAction* eact = create_adjustment_action( "WiggleAction",
2484 _("Wiggle:"), _("Increase to make the pen waver and wiggle"),
2485 "tools.calligraphic", "wiggle", 0.0,
2486 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2487 0.0, 1.0, 0.01, 0.1,
2488 labels, values, G_N_ELEMENTS(labels),
2489 sp_ddc_wiggle_value_changed, 0.01, 2 );
2490 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2491 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2492 }
2494 {
2495 /* Mass */
2496 gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
2497 gdouble values[] = {0.0, 0.02, 0.1, 0.2, 0.5, 1.0};
2498 EgeAdjustmentAction* eact = create_adjustment_action( "MassAction",
2499 _("Mass:"), _("Increase to make the pen drag behind, as if slowed by inertia"),
2500 "tools.calligraphic", "mass", 0.02,
2501 GTK_WIDGET(desktop->canvas), NULL, holder, FALSE, NULL,
2502 0.0, 1.0, 0.01, 0.1,
2503 labels, values, G_N_ELEMENTS(labels),
2504 sp_ddc_mass_value_changed, 0.01, 2 );
2505 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2506 gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
2507 }
2510 /* Trace Background button */
2511 {
2512 InkToggleAction* act = ink_toggle_action_new( "TraceAction",
2513 _("Trace Background"),
2514 _("Trace the lightness of the background by the width of the pen (white - minimum width, black - maximum width)"),
2515 "trace_background",
2516 Inkscape::ICON_SIZE_DECORATION );
2517 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2518 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_trace_background_changed), NULL);
2519 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "tracebackground", 0 ) );
2520 }
2522 /* Use Pressure button */
2523 {
2524 InkToggleAction* act = ink_toggle_action_new( "PressureAction",
2525 _("Pressure"),
2526 _("Use the pressure of the input device to alter the width of the pen"),
2527 "use_pressure",
2528 Inkscape::ICON_SIZE_DECORATION );
2529 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2530 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_pressure_state_changed), NULL);
2531 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usepressure", 1 ) );
2532 }
2534 /* Use Tilt button */
2535 {
2536 InkToggleAction* act = ink_toggle_action_new( "TiltAction",
2537 _("Tilt"),
2538 _("Use the tilt of the input device to alter the angle of the pen's nib"),
2539 "use_tilt",
2540 Inkscape::ICON_SIZE_DECORATION );
2541 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2542 g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_ddc_tilt_state_changed), calligraphy_angle );
2543 gtk_action_set_sensitive( GTK_ACTION(calligraphy_angle), !prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2544 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs_get_int_attribute( "tools.calligraphic", "usetilt", 1 ) );
2545 }
2547 /* Reset */
2548 {
2549 GtkAction* act = gtk_action_new( "CalligraphyResetAction",
2550 _("Defaults"),
2551 _("Reset shape parameters to defaults (use Inkscape Preferences > Tools to change defaults)"),
2552 GTK_STOCK_CLEAR );
2553 g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_ddc_defaults), holder );
2554 gtk_action_group_add_action( mainActions, act );
2555 gtk_action_set_sensitive( act, TRUE );
2556 }
2557 }
2558 }
2561 //########################
2562 //## Circle / Arc ##
2563 //########################
2565 static void sp_arctb_sensitivize( GObject *tbl, double v1, double v2 )
2566 {
2567 GtkAction *ocb = GTK_ACTION( g_object_get_data( tbl, "open_action" ) );
2568 GtkAction *make_whole = GTK_ACTION( g_object_get_data( tbl, "make_whole" ) );
2570 if (v1 == 0 && v2 == 0) {
2571 if (g_object_get_data( tbl, "single" )) { // only for a single selected ellipse (for now)
2572 gtk_action_set_sensitive( ocb, FALSE );
2573 gtk_action_set_sensitive( make_whole, FALSE );
2574 }
2575 } else {
2576 gtk_action_set_sensitive( ocb, TRUE );
2577 gtk_action_set_sensitive( make_whole, TRUE );
2578 }
2579 }
2581 static void
2582 sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *value_name, gchar const *other_name)
2583 {
2584 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2586 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2587 prefs_set_double_attribute("tools.shapes.arc", value_name, (adj->value * M_PI)/ 180);
2588 }
2590 // quit if run by the attr_changed listener
2591 if (g_object_get_data( tbl, "freeze" )) {
2592 return;
2593 }
2595 // in turn, prevent listener from responding
2596 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2598 gchar* namespaced_name = g_strconcat("sodipodi:", value_name, NULL);
2600 bool modmade = false;
2601 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2602 items != NULL;
2603 items = items->next)
2604 {
2605 SPItem *item = SP_ITEM(items->data);
2607 if (SP_IS_ARC(item) && SP_IS_GENERICELLIPSE(item)) {
2609 SPGenericEllipse *ge = SP_GENERICELLIPSE(item);
2610 SPArc *arc = SP_ARC(item);
2612 if (!strcmp(value_name, "start"))
2613 ge->start = (adj->value * M_PI)/ 180;
2614 else
2615 ge->end = (adj->value * M_PI)/ 180;
2617 sp_genericellipse_normalize(ge);
2618 ((SPObject *)arc)->updateRepr();
2619 ((SPObject *)arc)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
2621 modmade = true;
2622 }
2623 }
2625 g_free(namespaced_name);
2627 GtkAdjustment *other = GTK_ADJUSTMENT( g_object_get_data( tbl, other_name ) );
2629 sp_arctb_sensitivize( tbl, adj->value, other->value );
2631 if (modmade) {
2632 sp_document_maybe_done(sp_desktop_document(desktop), value_name, SP_VERB_CONTEXT_ARC,
2633 _("Arc: Change start/end"));
2634 }
2636 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2637 }
2640 static void sp_arctb_start_value_changed(GtkAdjustment *adj, GObject *tbl)
2641 {
2642 sp_arctb_startend_value_changed(adj, tbl, "start", "end");
2643 }
2645 static void sp_arctb_end_value_changed(GtkAdjustment *adj, GObject *tbl)
2646 {
2647 sp_arctb_startend_value_changed(adj, tbl, "end", "start");
2648 }
2650 static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
2651 {
2652 SPDesktop *desktop = (SPDesktop *) g_object_get_data( tbl, "desktop" );
2653 if (sp_document_get_undo_sensitive(sp_desktop_document(desktop))) {
2654 if ( ege_select_one_action_get_active( act ) != 0 ) {
2655 prefs_set_string_attribute("tools.shapes.arc", "open", "true");
2656 } else {
2657 prefs_set_string_attribute("tools.shapes.arc", "open", NULL);
2658 }
2659 }
2661 // quit if run by the attr_changed listener
2662 if (g_object_get_data( tbl, "freeze" )) {
2663 return;
2664 }
2666 // in turn, prevent listener from responding
2667 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2669 bool modmade = false;
2671 if ( ege_select_one_action_get_active(act) != 0 ) {
2672 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2673 items != NULL;
2674 items = items->next)
2675 {
2676 if (SP_IS_ARC((SPItem *) items->data)) {
2677 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2678 repr->setAttribute("sodipodi:open", "true");
2679 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2680 modmade = true;
2681 }
2682 }
2683 } else {
2684 for (GSList const *items = sp_desktop_selection(desktop)->itemList();
2685 items != NULL;
2686 items = items->next)
2687 {
2688 if (SP_IS_ARC((SPItem *) items->data)) {
2689 Inkscape::XML::Node *repr = SP_OBJECT_REPR((SPItem *) items->data);
2690 repr->setAttribute("sodipodi:open", NULL);
2691 SP_OBJECT((SPItem *) items->data)->updateRepr(repr, SP_OBJECT_WRITE_EXT);
2692 modmade = true;
2693 }
2694 }
2695 }
2697 if (modmade) {
2698 sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_ARC,
2699 _("Arc: Change open/closed"));
2700 }
2702 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2703 }
2705 static void sp_arctb_defaults(GtkWidget *, GObject *obj)
2706 {
2707 GtkAdjustment *adj;
2708 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "start") );
2709 gtk_adjustment_set_value(adj, 0.0);
2710 gtk_adjustment_value_changed(adj);
2712 adj = GTK_ADJUSTMENT( g_object_get_data(obj, "end") );
2713 gtk_adjustment_set_value(adj, 0.0);
2714 gtk_adjustment_value_changed(adj);
2716 spinbutton_defocus( GTK_OBJECT(obj) );
2717 }
2719 static void arc_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *name,
2720 gchar const *old_value, gchar const *new_value,
2721 bool is_interactive, gpointer data)
2722 {
2723 GObject *tbl = G_OBJECT(data);
2725 // quit if run by the _changed callbacks
2726 if (g_object_get_data( tbl, "freeze" )) {
2727 return;
2728 }
2730 // in turn, prevent callbacks from responding
2731 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
2733 gdouble start = sp_repr_get_double_attribute(repr, "sodipodi:start", 0.0);
2734 gdouble end = sp_repr_get_double_attribute(repr, "sodipodi:end", 0.0);
2736 GtkAdjustment *adj1,*adj2;
2737 adj1 = GTK_ADJUSTMENT( g_object_get_data( tbl, "start" ) );
2738 gtk_adjustment_set_value(adj1, mod360((start * 180)/M_PI));
2739 adj2 = GTK_ADJUSTMENT( g_object_get_data( tbl, "end" ) );
2740 gtk_adjustment_set_value(adj2, mod360((end * 180)/M_PI));
2742 sp_arctb_sensitivize( tbl, adj1->value, adj2->value );
2744 char const *openstr = NULL;
2745 openstr = repr->attribute("sodipodi:open");
2746 EgeSelectOneAction *ocb = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "open_action" ) );
2748 if (openstr) {
2749 ege_select_one_action_set_active( ocb, 1 );
2750 } else {
2751 ege_select_one_action_set_active( ocb, 0 );
2752 }
2754 g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
2755 }
2757 static Inkscape::XML::NodeEventVector arc_tb_repr_events = {
2758 NULL, /* child_added */
2759 NULL, /* child_removed */
2760 arc_tb_event_attr_changed,
2761 NULL, /* content_changed */
2762 NULL /* order_changed */
2763 };
2766 static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
2767 {
2768 int n_selected = 0;
2769 Inkscape::XML::Node *repr = NULL;
2770 Inkscape::XML::Node *oldrepr = NULL;
2772 for (GSList const *items = selection->itemList();
2773 items != NULL;
2774 items = items->next)
2775 {
2776 if (SP_IS_ARC((SPItem *) items->data)) {
2777 n_selected++;
2778 repr = SP_OBJECT_REPR((SPItem *) items->data);
2779 }
2780 }
2782 EgeOutputAction* act = EGE_OUTPUT_ACTION( g_object_get_data( tbl, "mode_action" ) );
2784 g_object_set_data( tbl, "single", GINT_TO_POINTER(FALSE) );
2785 if (n_selected == 0) {
2786 g_object_set( G_OBJECT(act), "label", _("<b>New:</b>"), NULL );
2787 } else if (n_selected == 1) {
2788 g_object_set_data( tbl, "single", GINT_TO_POINTER(TRUE) );
2789 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2791 oldrepr = (Inkscape::XML::Node *) g_object_get_data( tbl, "repr" );
2793 if (oldrepr) { // remove old listener
2794 sp_repr_remove_listener_by_data(oldrepr, tbl);
2795 Inkscape::GC::release(oldrepr);
2796 oldrepr = 0;
2797 g_object_set_data( tbl, "repr", NULL );
2798 }
2800 if (repr) {
2801 g_object_set_data( tbl, "repr", repr );
2802 Inkscape::GC::anchor(repr);
2803 sp_repr_add_listener(repr, &arc_tb_repr_events, tbl);
2804 sp_repr_synthesize_events(repr, &arc_tb_repr_events, tbl);
2805 }
2806 } else {
2807 // FIXME: implement averaging of all parameters for multiple selected
2808 //gtk_label_set_markup(GTK_LABEL(l), _("<b>Average:</b>"));
2809 g_object_set( G_OBJECT(act), "label", _("<b>Change:</b>"), NULL );
2810 sp_arctb_sensitivize( tbl, 1, 0 );
2811 }
2812 }
2815 static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
2816 {
2817 EgeAdjustmentAction* eact = 0;
2820 {
2821 EgeOutputAction* act = ege_output_action_new( "ArcStateAction", _("<b>New:</b>"), "", 0 );
2822 ege_output_action_set_use_markup( act, TRUE );
2823 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
2824 g_object_set_data( holder, "mode_action", act );
2825 }
2827 /* Start */
2828 {
2829 eact = create_adjustment_action( "ArcStartAction",
2830 _("Start:"), _("The angle (in degrees) from the horizontal to the arc's start point"),
2831 "tools.shapes.arc", "start", 0.0,
2832 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE, "altx-arc",
2833 -360.0, 360.0, 1.0, 10.0,
2834 0, 0, 0,
2835 sp_arctb_start_value_changed);
2836 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2837 }
2839 /* End */
2840 {
2841 eact = create_adjustment_action( "ArcEndAction",
2842 _("End:"), _("The angle (in degrees) from the horizontal to the arc's end point"),
2843 "tools.shapes.arc", "end", 0.0,
2844 GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, FALSE, NULL,
2845 -360.0, 360.0, 1.0, 10.0,
2846 0, 0, 0,
2847 sp_arctb_end_value_changed);
2848 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
2849 }
2851 /* Segments / Pie checkbox */
2852 {
2853 GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
2855 GtkTreeIter iter;
2856 gtk_list_store_append( model, &iter );
2857 gtk_list_store_set( model, &iter,
2858 0, _("Closed arc"),
2859 1, _("Switch to segment (closed shape with two radii)"),
2860 2, "circle_closed_arc",
2861 -1 );
2863 gtk_list_store_append( model, &iter );
2864 gtk_list_store_set( model, &iter,
2865 0, _("Open Arc"),
2866 1, _("Switch to arc (unclosed shape)"),
2867 2, "circle_open_arc",
2868 -1 );
2870 EgeSelectOneAction* act = ege_select_one_action_new( "ArcOpenAction", _(""), _(""), NULL, GTK_TREE_MODEL(model) );
2871 gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
2872 g_object_set_data( holder, "open_action", act );
2874 ege_select_one_action_set_appearance( act, "full" );
2875 ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
2876 g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
2877 ege_select_one_action_set_icon_column( act, 2 );
2878 ege_select_one_action_set_tooltip_column( act, 1 );
2880 gchar const *openstr = prefs_get_string_attribute("tools.shapes.arc", "open");
2881 bool isClosed = (!openstr || (openstr && !strcmp(openstr, "false")));
2882 ege_select_one_action_set_active( act, isClosed ? 0 : 1 );
2883 g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_arctb_open_state_changed), holder );
2884 }
2886 /* Make Whole */
2887 {
2888 InkAction* inky = ink_action_new( "ArcResetAction",
2889 _("Make whole"),
2890 _("Make the shape a whole ellipse, not arc or segment"),
2891 "reset_circle",
2892 Inkscape::ICON_SIZE_SMALL_TOOLBAR );
2893 g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_arctb_defaults), holder );
2894 gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
2895 gtk_action_set_sensitive( GTK_ACTION(inky), TRUE );
2896 g_object_set_data( holder, "make_whole", inky );
2897 }
2899 g_object_set_data( G_OBJECT(holder), "single", GINT_TO_POINTER(TRUE) );
2900 // sensitivize make whole and open checkbox
2901 {
2902 GtkAdjustment *adj1 = GTK_ADJUSTMENT( g_object_get_data( holder, "start" ) );
2903 GtkAdjustment *adj2 = GTK_ADJUSTMENT( g_object_get_data( holder, "end" ) );
2904 sp_arctb_sensitivize( holder, adj1->value, adj2->value );
2905 }
2908 sigc::connection *connection = new sigc::connection(
2909 sp_desktop_selection(desktop)->connectChanged(sigc::bind(sigc::ptr_fun(sp_arc_toolbox_selection_changed), (GObject *)holder))
2910 );
2911 g_signal_connect( holder, "destroy", G_CALLBACK(delete_connection), connection );
2912 }
2917 // toggle button callbacks and updaters
2919 //########################
2920 //## Dropper ##
2921 //########################
2923 static void toggle_dropper_pick_alpha (GtkWidget *button, gpointer tbl) {
2924 prefs_set_int_attribute ("tools.dropper", "pick",
2925 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)));
2926 GtkWidget *set_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "set_checkbox");
2927 if (set_checkbox) {
2928 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
2929 gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), TRUE);
2930 } else {
2931 gtk_widget_set_sensitive (GTK_WIDGET (set_checkbox), FALSE);
2932 }
2933 }
2934 spinbutton_defocus(GTK_OBJECT(tbl));
2935 }
2937 static void toggle_dropper_set_alpha (GtkWidget *button, gpointer tbl) {
2938 prefs_set_int_attribute ("tools.dropper", "setalpha",
2939 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)) ? 1 : 0);
2940 spinbutton_defocus(GTK_OBJECT(tbl));
2941 }
2944 /**
2945 * Copy the current saved desktop color to the clipboard as full hex + alpha
2946 * color representation. This is useful for passing values between various
2947 * input boxes, or directly to xml.
2948 */
2949 /* static void
2950 sp_dropper_copy( GtkWidget *widget, GtkObject *obj)
2951 {
2952 GtkWidget *tbl = GTK_WIDGET(obj);
2954 SPDesktop *desktop =
2955 (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2958 sp_dropper_c32_color_copy( sp_desktop_get_color(desktop, true) );
2959 }*/
2962 /**
2963 * Copies currently saved desktop color to the clipboard as a hex value. This
2964 * is useful for editing webpages and needing a value quickly for web
2965 * colors.
2966 *
2967 * TODO: When the toggle of the dropper is set to not mix color against
2968 * page background, this still just gets the color of the page and
2969 * doesn't get the actual mixed against background which is needed
2970 * for the hex value ppl. want for web pages, etc.
2971 */
2973 /* static void
2974 sp_dropper_copy_as_hex ( GtkWidget *widget, GtkObject *obj)
2975 {
2976 GtkWidget *tbl = GTK_WIDGET(obj);
2978 SPDesktop *desktop =
2979 (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl), "desktop");
2981 sp_dropper_c32_color_copy_hex( sp_desktop_get_color(desktop, true) );
2982 }*/
2985 /**
2986 * Sets the input boxes with the changed color and opacity. This is used as a
2987 * callback for style changing.
2988 */
2989 /* static bool
2990 sp_style_changed (const SPCSSAttr *css, gpointer data)
2991 {
2992 // GrDrag *drag = (GrDrag *) data;
2994 // set fill of text entry box
2995 if (css->attribute("fill"))
2996 gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
2997 css->attribute("fill"));
2999 // set opacity of text entry box
3000 if (css->attribute("fill-opacity"))
3001 gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
3002 css->attribute("fill-opacity"));
3004 // set fill of text entry box
3005 if (css->attribute("stroke"))
3006 gtk_entry_set_text((GtkEntry *)dropper_rgb_entry,
3007 css->attribute("stroke"));
3009 // set opacity of text entry box
3010 if (css->attribute("stroke-opacity"))
3011 gtk_entry_set_text((GtkEntry *)dropper_opacity_entry,
3012 css->attribute("stroke-opacity"));
3013 return false;
3015 }
3016 */
3019 /**
3020 * Dropper auxiliary toolbar construction and setup.
3021 *
3022 * TODO: Would like to add swatch of current color.
3023 * TODO: Add queue of last 5 or so colors selected with new swatches so that
3024 * can drag and drop places. Will provide a nice mixing palette.
3025 */
3026 static GtkWidget *
3027 sp_dropper_toolbox_new(SPDesktop *desktop)
3028 {
3029 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
3031 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3032 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3034 GtkTooltips *tt = gtk_tooltips_new();
3037 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
3038 AUX_BETWEEN_BUTTON_GROUPS);
3039 // sp_toolbox_add_label(tbl, _("<b>New:</b>"));
3043 /* RGB Input Field */
3044 /* {
3045 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3046 GtkWidget *dropper_rgba_label = gtk_label_new ("Color:");
3047 gtk_widget_show (dropper_rgba_label);
3048 gtk_container_add(GTK_CONTAINER(hb), dropper_rgba_label);
3050 dropper_rgb_entry = gtk_entry_new ();
3051 sp_dialog_defocus_on_enter (dropper_rgb_entry);
3052 gtk_entry_set_max_length (GTK_ENTRY (dropper_rgb_entry), 7);
3053 gtk_entry_set_width_chars (GTK_ENTRY (dropper_rgb_entry), 7);
3054 gtk_tooltips_set_tip(tt, dropper_rgb_entry,
3055 _("Hexidecimal representation of last selected "
3056 "color"),
3057 NULL);
3058 gtk_widget_show (dropper_rgb_entry);
3059 gtk_container_add(GTK_CONTAINER(hb), dropper_rgb_entry);
3061 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3062 AUX_BETWEEN_BUTTON_GROUPS);
3063 } */
3065 /* Opacity Input Field */
3066 /* {
3067 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3068 GtkWidget *dropper_opacity_label = gtk_label_new ( _("Opacity:") );
3069 gtk_widget_show (dropper_opacity_label);
3070 gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_label);
3072 dropper_opacity_entry = gtk_entry_new ();
3073 sp_dialog_defocus_on_enter (dropper_opacity_entry);
3074 gtk_entry_set_max_length (GTK_ENTRY (dropper_opacity_entry), 11);
3075 gtk_entry_set_width_chars (GTK_ENTRY (dropper_opacity_entry), 11);
3076 gtk_tooltips_set_tip(tt, dropper_opacity_entry,
3077 _("Opacity of last selected color"),
3078 NULL);
3079 gtk_widget_show (dropper_opacity_entry);
3080 gtk_container_add(GTK_CONTAINER(hb), dropper_opacity_entry);
3082 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3083 AUX_BETWEEN_BUTTON_GROUPS);
3084 } */
3087 /* Copy to Clipboard */
3088 /* {
3089 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3090 GtkWidget *b = gtk_button_new_with_label(_("Copy as RGBA"));
3091 gtk_tooltips_set_tip(tt, b, _("Copy last saved color as hexidecimal "
3092 "RGB + Alpha (RGBA) to "
3093 "clipboard"),
3094 NULL);
3095 gtk_widget_show(b);
3096 gtk_container_add(GTK_CONTAINER(hb), b);
3097 gtk_signal_connect(GTK_OBJECT(b), "clicked",
3098 GTK_SIGNAL_FUNC(sp_dropper_copy), tbl);
3099 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3100 AUX_BETWEEN_BUTTON_GROUPS);
3101 } */
3104 /* Copy to Clipboard as HEX */
3105 /* {
3106 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3107 GtkWidget *b = gtk_button_new_with_label(_("Copy as HEX"));
3108 gtk_tooltips_set_tip(tt, b, _("Copy last saved color as "
3109 "hexidecimal RGB without alpha "
3110 "to clipboard"), NULL);
3111 gtk_widget_show(b);
3112 gtk_container_add(GTK_CONTAINER(hb), b);
3113 gtk_signal_connect(GTK_OBJECT(b), "clicked",
3114 GTK_SIGNAL_FUNC(sp_dropper_copy_as_hex), tbl);
3115 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3116 AUX_BETWEEN_BUTTON_GROUPS);
3117 } */
3119 // aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3121 {
3122 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3124 GtkWidget *button = gtk_check_button_new_with_label(_("Pick alpha"));
3125 gtk_tooltips_set_tip(tt, button, _("Pick both the color and the alpha (transparency) under cursor; otherwise, pick only the visible color premultiplied by alpha"), NULL);
3126 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
3127 prefs_get_int_attribute ("tools.dropper",
3128 "pick", 1));
3129 gtk_widget_show(button);
3130 gtk_container_add (GTK_CONTAINER (hb), button);
3131 gtk_object_set_data(GTK_OBJECT(tbl), "pick_checkbox", button);
3132 g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_pick_alpha), tbl);
3133 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3134 AUX_BETWEEN_BUTTON_GROUPS);
3135 }
3137 {
3138 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
3140 GtkWidget *button = gtk_check_button_new_with_label(_("Set alpha"));
3141 gtk_tooltips_set_tip(tt, button, _("If alpha was picked, assign it to selection as fill or stroke transparency"), NULL);
3142 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
3143 prefs_get_int_attribute ("tools.dropper",
3144 "setalpha", 1));
3145 gtk_widget_show(button);
3146 gtk_container_add (GTK_CONTAINER (hb), button);
3147 gtk_object_set_data(GTK_OBJECT(tbl), "set_checkbox", button);
3148 g_signal_connect (G_OBJECT (button), "toggled", G_CALLBACK (toggle_dropper_set_alpha), tbl);
3150 // make sure it's disabled if we're not picking alpha
3151 GtkWidget *pick_checkbox = (GtkWidget*) g_object_get_data(G_OBJECT(tbl), "pick_checkbox");
3152 if (pick_checkbox) {
3153 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pick_checkbox))) {
3154 gtk_widget_set_sensitive (GTK_WIDGET (button), TRUE);
3155 } else {
3156 gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
3157 }
3158 }
3160 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE,
3161 AUX_BETWEEN_BUTTON_GROUPS);
3162 }
3164 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
3167 // where new gtkmm stuff should go
3169 gtk_widget_show_all(tbl);
3170 sp_set_font_size_smaller (tbl);
3172 /*
3173 sigc::connection *connection = new sigc::connection(
3174 desktop->connectSetStyle(
3175 sigc::bind(sigc::ptr_fun(sp_style_changed),
3176 desktop)) );
3178 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_connection),
3179 connection); */
3181 return tbl;
3182 }
3185 //########################
3186 //## Text Toolbox ##
3187 //########################
3188 /*
3189 static void
3190 sp_text_letter_changed(GtkAdjustment *adj, GtkWidget *tbl)
3191 {
3192 //Call back for letter sizing spinbutton
3193 }
3195 static void
3196 sp_text_line_changed(GtkAdjustment *adj, GtkWidget *tbl)
3197 {
3198 //Call back for line height spinbutton
3199 }
3201 static void
3202 sp_text_horiz_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3203 {
3204 //Call back for horizontal kerning spinbutton
3205 }
3207 static void
3208 sp_text_vert_kern_changed(GtkAdjustment *adj, GtkWidget *tbl)
3209 {
3210 //Call back for vertical kerning spinbutton
3211 }
3213 static void
3214 sp_text_letter_rotation_changed(GtkAdjustment *adj, GtkWidget *tbl)
3215 {
3216 //Call back for letter rotation spinbutton
3217 }*/
3219 namespace {
3221 bool visible = false;
3223 void
3224 sp_text_toolbox_selection_changed (Inkscape::Selection *selection, GObject *tbl)
3225 {
3227 SPStyle *query =
3228 sp_style_new ();
3230 int result_family =
3231 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTFAMILY);
3233 int result_style =
3234 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTSTYLE);
3236 int result_numbers =
3237 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3239 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3241 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3242 if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING)
3243 {
3244 Inkscape::XML::Node *repr = inkscape_get_repr (INKSCAPE, "tools.text");
3246 if (repr)
3247 {
3248 sp_style_read_from_repr (query, repr);
3249 }
3250 else
3251 {
3252 return;
3253 }
3254 }
3256 if (query->text)
3257 {
3258 if (result_family == QUERY_STYLE_MULTIPLE_DIFFERENT) {
3259 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3260 gtk_entry_set_text (GTK_ENTRY (entry), "");
3262 } else if (query->text->font_family.value) {
3264 GtkWidget *entry = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "family-entry"));
3265 gtk_entry_set_text (GTK_ENTRY (entry), query->text->font_family.value);
3267 Gtk::TreePath path;
3268 try {
3269 path = Inkscape::FontLister::get_instance()->get_row_for_font (query->text->font_family.value);
3270 } catch (...) {
3271 return;
3272 }
3274 GtkTreeSelection *tselection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3275 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3277 g_object_set_data (G_OBJECT (tselection), "block", gpointer(1));
3279 gtk_tree_selection_select_path (tselection, path.gobj());
3280 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3282 g_object_set_data (G_OBJECT (tselection), "block", gpointer(0));
3283 }
3285 //Size
3286 GtkWidget *cbox = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "combo-box-size"));
3287 char *str = g_strdup_printf ("%.5g", query->font_size.computed);
3288 g_object_set_data (tbl, "size-block", gpointer(1));
3289 gtk_entry_set_text (GTK_ENTRY(GTK_BIN (cbox)->child), str);
3290 g_object_set_data (tbl, "size-block", gpointer(0));
3291 free (str);
3293 //Anchor
3294 if (query->text_align.computed == SP_CSS_TEXT_ALIGN_JUSTIFY)
3295 {
3296 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-fill"));
3297 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3298 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3299 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3300 }
3301 else
3302 {
3303 if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_START)
3304 {
3305 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-start"));
3306 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3307 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3308 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3309 }
3310 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE)
3311 {
3312 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-middle"));
3313 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3314 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3315 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3316 }
3317 else if (query->text_anchor.computed == SP_CSS_TEXT_ANCHOR_END)
3318 {
3319 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "text-end"));
3320 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3321 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3322 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3323 }
3324 }
3326 //Style
3327 {
3328 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-bold"));
3330 gboolean active = gtk_toggle_button_get_active (button);
3331 gboolean check = (query->font_weight.computed >= SP_CSS_FONT_WEIGHT_700);
3333 if (active != check)
3334 {
3335 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3336 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3337 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3338 }
3339 }
3341 {
3342 GtkToggleButton *button = GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (tbl), "style-italic"));
3344 gboolean active = gtk_toggle_button_get_active (button);
3345 gboolean check = (query->font_style.computed != SP_CSS_FONT_STYLE_NORMAL);
3347 if (active != check)
3348 {
3349 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3350 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), check);
3351 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3352 }
3353 }
3355 //Orientation
3356 //locking both buttons, changing one affect all group (both)
3357 GtkWidget *button = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-horizontal"));
3358 g_object_set_data (G_OBJECT (button), "block", gpointer(1));
3360 GtkWidget *button1 = GTK_WIDGET (g_object_get_data (G_OBJECT (tbl), "orientation-vertical"));
3361 g_object_set_data (G_OBJECT (button1), "block", gpointer(1));
3363 if (query->writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB)
3364 {
3365 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3366 }
3367 else
3368 {
3369 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button1), TRUE);
3370 }
3371 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3372 g_object_set_data (G_OBJECT (button1), "block", gpointer(0));
3373 }
3374 }
3376 void
3377 sp_text_toolbox_selection_modified (Inkscape::Selection *selection, guint flags, GObject *tbl)
3378 {
3379 sp_text_toolbox_selection_changed (selection, tbl);
3380 }
3382 void
3383 sp_text_toolbox_subselection_changed (gpointer dragger, GObject *tbl)
3384 {
3385 sp_text_toolbox_selection_changed (NULL, tbl);
3386 }
3388 void
3389 sp_text_toolbox_family_changed (GtkTreeSelection *selection,
3390 GObject *tbl)
3391 {
3392 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3393 GtkTreeModel *model = 0;
3394 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3395 GtkWidget *entry = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3396 GtkTreeIter iter;
3397 char *family = 0;
3399 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3400 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3402 if ( !gtk_tree_selection_get_selected( selection, &model, &iter ) ) {
3403 return;
3404 }
3406 gtk_tree_model_get (model, &iter, 0, &family, -1);
3408 if (g_object_get_data (G_OBJECT (selection), "block"))
3409 {
3410 gtk_entry_set_text (GTK_ENTRY (entry), family);
3411 return;
3412 }
3414 gtk_widget_hide (popdown);
3415 visible = false;
3417 gtk_entry_set_text (GTK_ENTRY (entry), family);
3419 SPStyle *query =
3420 sp_style_new ();
3422 int result_numbers =
3423 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3425 SPCSSAttr *css = sp_repr_css_attr_new ();
3426 sp_repr_css_set_property (css, "font-family", family);
3428 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3429 if (result_numbers == QUERY_STYLE_NOTHING)
3430 {
3431 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3432 sp_text_edit_dialog_default_set_insensitive (); //FIXME: Replace trough a verb
3433 }
3434 else
3435 {
3436 sp_desktop_set_style (desktop, css, true, true);
3437 }
3439 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3440 _("Text: Change font family"));
3441 sp_repr_css_attr_unref (css);
3442 free (family);
3443 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3445 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3446 }
3448 void
3449 sp_text_toolbox_family_entry_activate (GtkEntry *entry,
3450 GObject *tbl)
3451 {
3452 const char *family = gtk_entry_get_text (entry);
3454 try {
3455 Gtk::TreePath path = Inkscape::FontLister::get_instance()->get_row_for_font (family);
3456 GtkTreeSelection *selection = GTK_TREE_SELECTION (g_object_get_data (G_OBJECT(tbl), "family-tree-selection"));
3457 GtkTreeView *treeview = GTK_TREE_VIEW (g_object_get_data (G_OBJECT(tbl), "family-tree-view"));
3458 gtk_tree_selection_select_path (selection, path.gobj());
3459 gtk_tree_view_scroll_to_cell (treeview, path.gobj(), NULL, TRUE, 0.5, 0.0);
3460 gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3461 } catch (...) {
3462 if (family && strlen (family))
3463 {
3464 gtk_widget_show_all (GTK_WIDGET (g_object_get_data (G_OBJECT(tbl), "warning-image")));
3465 }
3466 }
3467 }
3469 void
3470 sp_text_toolbox_anchoring_toggled (GtkRadioButton *button,
3471 gpointer data)
3472 {
3473 if (g_object_get_data (G_OBJECT (button), "block")) return;
3474 if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) return;
3475 int prop = GPOINTER_TO_INT(data);
3477 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3478 SPCSSAttr *css = sp_repr_css_attr_new ();
3480 switch (prop)
3481 {
3482 case 0:
3483 {
3484 sp_repr_css_set_property (css, "text-anchor", "start");
3485 sp_repr_css_set_property (css, "text-align", "start");
3486 break;
3487 }
3488 case 1:
3489 {
3490 sp_repr_css_set_property (css, "text-anchor", "middle");
3491 sp_repr_css_set_property (css, "text-align", "center");
3492 break;
3493 }
3495 case 2:
3496 {
3497 sp_repr_css_set_property (css, "text-anchor", "end");
3498 sp_repr_css_set_property (css, "text-align", "end");
3499 break;
3500 }
3502 case 3:
3503 {
3504 sp_repr_css_set_property (css, "text-anchor", "start");
3505 sp_repr_css_set_property (css, "text-align", "justify");
3506 break;
3507 }
3508 }
3510 SPStyle *query =
3511 sp_style_new ();
3512 int result_numbers =
3513 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3515 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3516 if (result_numbers == QUERY_STYLE_NOTHING)
3517 {
3518 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3519 }
3521 sp_desktop_set_style (desktop, css, true, true);
3522 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3523 _("Text: Change alignment"));
3524 sp_repr_css_attr_unref (css);
3526 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3527 }
3529 void
3530 sp_text_toolbox_style_toggled (GtkToggleButton *button,
3531 gpointer data)
3532 {
3533 if (g_object_get_data (G_OBJECT (button), "block")) return;
3535 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3536 SPCSSAttr *css = sp_repr_css_attr_new ();
3537 int prop = GPOINTER_TO_INT(data);
3538 bool active = gtk_toggle_button_get_active (button);
3541 switch (prop)
3542 {
3543 case 0:
3544 {
3545 sp_repr_css_set_property (css, "font-weight", active ? "bold" : "normal" );
3546 break;
3547 }
3549 case 1:
3550 {
3551 sp_repr_css_set_property (css, "font-style", active ? "italic" : "normal");
3552 break;
3553 }
3554 }
3556 SPStyle *query =
3557 sp_style_new ();
3558 int result_numbers =
3559 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3561 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3562 if (result_numbers == QUERY_STYLE_NOTHING)
3563 {
3564 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3565 }
3567 sp_desktop_set_style (desktop, css, true, true);
3568 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3569 _("Text: Change font style"));
3570 sp_repr_css_attr_unref (css);
3572 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3573 }
3575 void
3576 sp_text_toolbox_orientation_toggled (GtkRadioButton *button,
3577 gpointer data)
3578 {
3579 if (g_object_get_data (G_OBJECT (button), "block")) {
3580 g_object_set_data (G_OBJECT (button), "block", gpointer(0));
3581 return;
3582 }
3584 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3585 SPCSSAttr *css = sp_repr_css_attr_new ();
3586 int prop = GPOINTER_TO_INT(data);
3588 switch (prop)
3589 {
3590 case 0:
3591 {
3592 sp_repr_css_set_property (css, "writing-mode", "lr");
3593 break;
3594 }
3596 case 1:
3597 {
3598 sp_repr_css_set_property (css, "writing-mode", "tb");
3599 break;
3600 }
3601 }
3603 SPStyle *query =
3604 sp_style_new ();
3605 int result_numbers =
3606 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3608 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3609 if (result_numbers == QUERY_STYLE_NOTHING)
3610 {
3611 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3612 }
3614 sp_desktop_set_style (desktop, css, true, true);
3615 sp_document_done (sp_desktop_document (SP_ACTIVE_DESKTOP), SP_VERB_CONTEXT_TEXT,
3616 _("Text: Change orientation"));
3617 sp_repr_css_attr_unref (css);
3619 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3620 }
3622 gboolean
3623 sp_text_toolbox_size_keypress (GtkWidget *w, GdkEventKey *event, gpointer data)
3624 {
3625 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3626 if (!desktop) return FALSE;
3628 switch (get_group0_keyval (event)) {
3629 case GDK_Escape: // defocus
3630 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3631 return TRUE; // I consumed the event
3632 break;
3633 case GDK_Return: // defocus
3634 case GDK_KP_Enter:
3635 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3636 return TRUE; // I consumed the event
3637 break;
3638 }
3639 return FALSE;
3640 }
3642 gboolean
3643 sp_text_toolbox_family_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3644 {
3645 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3646 if (!desktop) return FALSE;
3648 switch (get_group0_keyval (event)) {
3649 case GDK_Escape: // defocus
3650 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3651 sp_text_toolbox_selection_changed (NULL, tbl); // update
3652 return TRUE; // I consumed the event
3653 break;
3654 }
3655 return FALSE;
3656 }
3658 gboolean
3659 sp_text_toolbox_family_list_keypress (GtkWidget *w, GdkEventKey *event, GObject *tbl)
3660 {
3661 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3662 if (!desktop) return FALSE;
3664 switch (get_group0_keyval (event)) {
3665 case GDK_Escape: // defocus
3666 gtk_widget_hide (w);
3667 visible = false;
3668 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3669 return TRUE; // I consumed the event
3670 break;
3671 }
3672 return FALSE;
3673 }
3676 void
3677 sp_text_toolbox_size_changed (GtkComboBox *cbox,
3678 GObject *tbl)
3679 {
3680 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3682 if (g_object_get_data (tbl, "size-block")) return;
3684 #if GTK_CHECK_VERSION(2,6,0)
3685 char *text = gtk_combo_box_get_active_text (cbox);
3686 #else // GTK_CHECK_VERSION(2,6,0)
3687 GtkTreeModel *model = gtk_combo_box_get_model (cbox);
3688 GtkTreeIter iter;
3689 char *text = NULL;
3691 if (gtk_combo_box_get_active_iter (cbox, &iter) && model)
3692 gtk_tree_model_get (model, &iter, 0, &text, -1);
3693 #endif // GTK_CHECK_VERSION(2,6,0)
3695 SPCSSAttr *css = sp_repr_css_attr_new ();
3696 sp_repr_css_set_property (css, "font-size", text);
3697 free (text);
3699 SPStyle *query =
3700 sp_style_new ();
3701 int result_numbers =
3702 sp_desktop_query_style (SP_ACTIVE_DESKTOP, query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
3704 // If querying returned nothing, read the style from the text tool prefs (default style for new texts)
3705 if (result_numbers == QUERY_STYLE_NOTHING)
3706 {
3707 sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.text"), css, "style");
3708 }
3710 sp_desktop_set_style (desktop, css, true, true);
3711 sp_document_maybe_done (sp_desktop_document (SP_ACTIVE_DESKTOP), "ttb:size", SP_VERB_NONE,
3712 _("Text: Change font size"));
3713 sp_repr_css_attr_unref (css);
3716 if (gtk_combo_box_get_active (cbox) > 0) // if this was from drop-down (as opposed to type-in), defocus
3717 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3718 }
3720 void
3721 sp_text_toolbox_text_popdown_clicked (GtkButton *button,
3722 GObject *tbl)
3723 {
3724 GtkWidget *popdown = GTK_WIDGET (g_object_get_data (tbl, "family-popdown-window"));
3725 GtkWidget *widget = GTK_WIDGET (g_object_get_data (tbl, "family-entry"));
3726 int x, y;
3728 if (!visible)
3729 {
3730 gdk_window_get_origin (widget->window, &x, &y);
3731 gtk_window_move (GTK_WINDOW (popdown), x, y + widget->allocation.height + 2); //2px of grace space
3732 gtk_widget_show_all (popdown);
3734 gdk_pointer_grab (widget->window, TRUE,
3735 GdkEventMask (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3736 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
3737 GDK_POINTER_MOTION_MASK),
3738 NULL, NULL, GDK_CURRENT_TIME);
3740 gdk_keyboard_grab (widget->window, TRUE, GDK_CURRENT_TIME);
3742 visible = true;
3743 }
3744 else
3745 {
3746 gdk_pointer_ungrab (GDK_CURRENT_TIME);
3747 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
3748 gtk_widget_hide (popdown);
3749 visible = false;
3750 }
3751 }
3753 gboolean
3754 sp_text_toolbox_entry_focus_in (GtkWidget *entry,
3755 GdkEventFocus *event,
3756 GObject *tbl)
3757 {
3758 gtk_entry_select_region (GTK_ENTRY (entry), 0, -1);
3759 return FALSE;
3760 }
3762 gboolean
3763 sp_text_toolbox_popdown_focus_out (GtkWidget *popdown,
3764 GdkEventFocus *event,
3765 GObject *tbl)
3766 {
3767 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
3769 gtk_widget_hide (popdown);
3770 visible = false;
3771 gtk_widget_grab_focus (GTK_WIDGET(desktop->canvas));
3772 return TRUE;
3773 }
3775 void
3776 cell_data_func (GtkTreeViewColumn *column,
3777 GtkCellRenderer *cell,
3778 GtkTreeModel *tree_model,
3779 GtkTreeIter *iter,
3780 gpointer data)
3781 {
3782 char *family,
3783 *family_escaped,
3784 *sample_escaped;
3786 static const char *sample = _("AaBbCcIiPpQq12369$\342\202\254\302\242?.;/()");
3788 gtk_tree_model_get (tree_model, iter, 0, &family, -1);
3790 family_escaped = g_markup_escape_text (family, -1);
3791 sample_escaped = g_markup_escape_text (sample, -1);
3793 std::stringstream markup;
3794 markup << family_escaped << " <span foreground='darkgray' font_family='" << family_escaped << "'>" << sample_escaped << "</span>";
3795 g_object_set (G_OBJECT (cell), "markup", markup.str().c_str(), NULL);
3797 free (family);
3798 free (family_escaped);
3799 free (sample_escaped);
3800 }
3802 static void delete_completion(GObject *obj, GtkWidget *entry) {
3803 GObject *completion = (GObject *) gtk_object_get_data(GTK_OBJECT(entry), "completion");
3804 if (completion) {
3805 gtk_entry_set_completion (GTK_ENTRY(entry), NULL);
3806 g_object_unref (completion);
3807 }
3808 }
3810 GtkWidget*
3811 sp_text_toolbox_new (SPDesktop *desktop)
3812 {
3813 GtkWidget *tbl = gtk_hbox_new (FALSE, 0);
3815 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
3816 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
3818 GtkTooltips *tt = gtk_tooltips_new();
3819 Glib::RefPtr<Gtk::ListStore> store = Inkscape::FontLister::get_instance()->get_font_list();
3821 ////////////Family
3822 //Window
3823 GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3824 gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
3826 //Entry
3827 GtkWidget *entry = gtk_entry_new ();
3828 gtk_object_set_data(GTK_OBJECT(entry), "altx-text", entry);
3829 GtkEntryCompletion *completion = gtk_entry_completion_new ();
3830 gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (Glib::unwrap(store)));
3831 gtk_entry_completion_set_text_column (completion, 0);
3832 gtk_entry_completion_set_minimum_key_length (completion, 1);
3833 g_object_set (G_OBJECT(completion), "inline-completion", TRUE, "popup-completion", TRUE, NULL);
3834 gtk_entry_set_completion (GTK_ENTRY(entry), completion);
3835 gtk_object_set_data(GTK_OBJECT(entry), "completion", completion);
3836 aux_toolbox_space (tbl, 1);
3837 gtk_box_pack_start (GTK_BOX (tbl), entry, FALSE, FALSE, 0);
3838 g_signal_connect(G_OBJECT(tbl), "destroy", G_CALLBACK(delete_completion), entry);
3840 //Button
3841 GtkWidget *button = gtk_button_new ();
3842 gtk_container_add (GTK_CONTAINER (button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
3843 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, 0);
3845 //Popdown
3846 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
3847 GtkWidget *treeview = gtk_tree_view_new ();
3849 GtkCellRenderer *cell = gtk_cell_renderer_text_new ();
3850 GtkTreeViewColumn *column = gtk_tree_view_column_new ();
3851 gtk_tree_view_column_pack_start (column, cell, FALSE);
3852 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
3853 gtk_tree_view_column_set_cell_data_func (column, cell, GtkTreeCellDataFunc (cell_data_func), NULL, NULL);
3854 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
3856 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (Glib::unwrap(store)));
3857 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
3858 #if GTK_CHECK_VERSION(2,6,0)
3859 gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
3860 #endif // GTK_CHECK_VERSION(2,6,0)
3862 //gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), TRUE);
3864 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
3865 gtk_container_add (GTK_CONTAINER (sw), treeview);
3867 gtk_container_add (GTK_CONTAINER (window), sw);
3868 gtk_widget_set_size_request (window, 300, 450);
3870 g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (sp_text_toolbox_family_entry_activate), tbl);
3871 g_signal_connect (G_OBJECT (entry), "focus-in-event", G_CALLBACK (sp_text_toolbox_entry_focus_in), tbl);
3872 g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK(sp_text_toolbox_family_keypress), tbl);
3874 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (sp_text_toolbox_text_popdown_clicked), tbl);
3876 g_signal_connect (G_OBJECT (window), "focus-out-event", G_CALLBACK (sp_text_toolbox_popdown_focus_out), tbl);
3877 g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(sp_text_toolbox_family_list_keypress), tbl);
3879 GtkTreeSelection *tselection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
3880 g_signal_connect (G_OBJECT (tselection), "changed", G_CALLBACK (sp_text_toolbox_family_changed), tbl);
3882 g_object_set_data (G_OBJECT (tbl), "family-entry", entry);
3883 g_object_set_data (G_OBJECT (tbl), "family-popdown-button", button);
3884 g_object_set_data (G_OBJECT (tbl), "family-popdown-window", window);
3885 g_object_set_data (G_OBJECT (tbl), "family-tree-selection", tselection);
3886 g_object_set_data (G_OBJECT (tbl), "family-tree-view", treeview);
3888 GtkWidget *image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
3889 aux_toolbox_space (tbl, 1);
3890 GtkWidget *box = gtk_event_box_new ();
3891 gtk_container_add (GTK_CONTAINER (box), image);
3892 gtk_box_pack_start (GTK_BOX (tbl), box, FALSE, FALSE, 4);
3893 g_object_set_data (G_OBJECT (tbl), "warning-image", box);
3894 GtkTooltips *tooltips = gtk_tooltips_new ();
3895 gtk_tooltips_set_tip (tooltips, box, _("This font is currently not installed on your system. Inkscape will use the default font instead."), "");
3896 gtk_widget_hide (GTK_WIDGET (box));
3897 g_signal_connect_swapped (G_OBJECT (tbl), "show", G_CALLBACK (gtk_widget_hide), box);
3899 ////////////Size
3900 const char *sizes[] = {
3901 "4", "6", "8", "9", "10", "11", "12", "13", "14",
3902 "16", "18", "20", "22", "24", "28",
3903 "32", "36", "40", "48", "56", "64", "72", "144"
3904 };
3906 GtkWidget *cbox = gtk_combo_box_entry_new_text ();
3907 for (unsigned int n = 0; n < G_N_ELEMENTS (sizes); gtk_combo_box_append_text (GTK_COMBO_BOX(cbox), sizes[n++]));
3908 gtk_widget_set_size_request (cbox, 80, -1);
3909 aux_toolbox_space (tbl, 1);
3910 gtk_box_pack_start (GTK_BOX (tbl), cbox, FALSE, FALSE, 0);
3911 g_object_set_data (G_OBJECT (tbl), "combo-box-size", cbox);
3912 g_signal_connect (G_OBJECT (cbox), "changed", G_CALLBACK (sp_text_toolbox_size_changed), tbl);
3913 gtk_signal_connect(GTK_OBJECT(cbox), "key-press-event", GTK_SIGNAL_FUNC(sp_text_toolbox_size_keypress), NULL);
3915 //spacer
3916 aux_toolbox_space (tbl, 4);
3917 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3919 ////////////Text anchor
3920 GtkWidget *group = gtk_radio_button_new (NULL);
3921 GtkWidget *row = gtk_hbox_new (FALSE, 4);
3922 g_object_set_data (G_OBJECT (tbl), "anchor-group", group);
3924 // left
3925 GtkWidget *rbutton = group;
3926 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3927 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_LEFT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3928 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3930 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3931 g_object_set_data (G_OBJECT (tbl), "text-start", rbutton);
3932 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(0));
3933 gtk_tooltips_set_tip(tt, rbutton, _("Align left"), NULL);
3935 // center
3936 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3937 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3938 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_CENTER, GTK_ICON_SIZE_SMALL_TOOLBAR));
3939 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3941 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3942 g_object_set_data (G_OBJECT (tbl), "text-middle", rbutton);
3943 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer (1));
3944 gtk_tooltips_set_tip(tt, rbutton, _("Center"), NULL);
3946 // right
3947 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3948 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3949 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_RIGHT, GTK_ICON_SIZE_SMALL_TOOLBAR));
3950 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3952 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3953 g_object_set_data (G_OBJECT (tbl), "text-end", rbutton);
3954 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(2));
3955 gtk_tooltips_set_tip(tt, rbutton, _("Align right"), NULL);
3957 // fill
3958 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
3959 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3960 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_JUSTIFY_FILL, GTK_ICON_SIZE_SMALL_TOOLBAR));
3961 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3963 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3964 g_object_set_data (G_OBJECT (tbl), "text-fill", rbutton);
3965 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_anchoring_toggled), gpointer(3));
3966 gtk_tooltips_set_tip(tt, rbutton, _("Justify"), NULL);
3968 aux_toolbox_space (tbl, 1);
3969 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
3971 //spacer
3972 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
3974 ////////////Text style
3975 row = gtk_hbox_new (FALSE, 4);
3977 // bold
3978 rbutton = gtk_toggle_button_new ();
3979 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3980 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_BOLD, GTK_ICON_SIZE_SMALL_TOOLBAR));
3981 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3982 gtk_tooltips_set_tip(tt, rbutton, _("Bold"), NULL);
3984 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3985 g_object_set_data (G_OBJECT (tbl), "style-bold", rbutton);
3986 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer(0));
3988 // italic
3989 rbutton = gtk_toggle_button_new ();
3990 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
3991 gtk_container_add (GTK_CONTAINER (rbutton), gtk_image_new_from_stock (GTK_STOCK_ITALIC, GTK_ICON_SIZE_SMALL_TOOLBAR));
3992 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
3993 gtk_tooltips_set_tip(tt, rbutton, _("Italic"), NULL);
3995 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
3996 g_object_set_data (G_OBJECT (tbl), "style-italic", rbutton);
3997 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_style_toggled), gpointer (1));
3999 aux_toolbox_space (tbl, 1);
4000 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4002 //spacer
4003 gtk_box_pack_start (GTK_BOX (tbl), gtk_vseparator_new (), FALSE, FALSE, 4);
4005 ////////////Text orientation
4006 group = gtk_radio_button_new (NULL);
4007 row = gtk_hbox_new (FALSE, 4);
4008 g_object_set_data (G_OBJECT (tbl), "orientation-group", group);
4010 // horizontal
4011 rbutton = group;
4012 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4013 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR));
4014 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4015 gtk_tooltips_set_tip(tt, rbutton, _("Horizontal text"), NULL);
4017 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4018 g_object_set_data (G_OBJECT (tbl), "orientation-horizontal", rbutton);
4019 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer(0));
4021 // vertical
4022 rbutton = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4023 gtk_button_set_relief (GTK_BUTTON (rbutton), GTK_RELIEF_NONE);
4024 gtk_container_add (GTK_CONTAINER (rbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB));
4025 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (rbutton), FALSE);
4026 gtk_tooltips_set_tip(tt, rbutton, _("Vertical text"), NULL);
4028 gtk_box_pack_start (GTK_BOX (row), rbutton, FALSE, FALSE, 0);
4029 g_object_set_data (G_OBJECT (tbl), "orientation-vertical", rbutton);
4030 g_signal_connect (G_OBJECT (rbutton), "toggled", G_CALLBACK (sp_text_toolbox_orientation_toggled), gpointer (1));
4031 gtk_box_pack_start (GTK_BOX (tbl), row, FALSE, FALSE, 4);
4034 //watch selection
4035 Inkscape::ConnectionPool* pool = Inkscape::ConnectionPool::new_connection_pool ("ISTextToolbox");
4037 sigc::connection *c_selection_changed =
4038 new sigc::connection (sp_desktop_selection (desktop)->connectChanged
4039 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_changed), (GObject*)tbl)));
4040 pool->add_connection ("selection-changed", c_selection_changed);
4042 sigc::connection *c_selection_modified =
4043 new sigc::connection (sp_desktop_selection (desktop)->connectModified
4044 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_selection_modified), (GObject*)tbl)));
4045 pool->add_connection ("selection-modified", c_selection_modified);
4047 sigc::connection *c_subselection_changed =
4048 new sigc::connection (desktop->connectToolSubselectionChanged
4049 (sigc::bind (sigc::ptr_fun (sp_text_toolbox_subselection_changed), (GObject*)tbl)));
4050 pool->add_connection ("tool-subselection-changed", c_subselection_changed);
4052 Inkscape::ConnectionPool::connect_destroy (G_OBJECT (tbl), pool);
4055 #if 0
4056 // horizontal
4057 {
4058 GtkWidget *px= sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_LR);
4059 GtkWidget *b = group = gtk_radio_button_new (NULL);
4060 gtk_container_add (GTK_CONTAINER (b), px);
4061 gtk_tooltips_set_tip (tt, b, _("Horizontal text"), NULL);
4062 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4063 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4064 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4065 }
4067 // vertical
4068 {
4069 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_WRITING_MODE_TB);
4070 GtkWidget *b = gtk_radio_button_new (gtk_radio_button_group (GTK_RADIO_BUTTON (group)));
4071 gtk_container_add (GTK_CONTAINER (b), px);
4072 gtk_tooltips_set_tip (tt, b, _("Vertical text"), NULL);
4073 gtk_button_set_relief (GTK_BUTTON (b), GTK_RELIEF_NONE);
4074 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (b), FALSE );
4075 gtk_box_pack_start (GTK_BOX (tbl), b, FALSE, FALSE, 0);
4076 }
4078 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4080 // letter spacing
4081 {
4082 {
4083 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LETTER_SPACING);
4084 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4085 gtk_container_add (GTK_CONTAINER (hb), image);
4086 gtk_widget_show(image);
4087 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4088 }
4090 {
4091 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between letters"),
4092 "tools.text", "letter_spacing", 0.0,
4093 us, tbl, FALSE, NULL,
4094 -1000.0, 1000.0, 0.1, 0.1,
4095 sp_text_letter_changed, 0.1, 1);
4096 gtk_widget_set_size_request (hb, 45, 6);
4097 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4098 }
4099 }
4101 // line spacing
4102 {
4103 {
4104 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_LINE_SPACING);
4105 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4106 gtk_container_add (GTK_CONTAINER (hb), image);
4107 gtk_widget_show(image);
4108 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4109 }
4111 {
4112 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Spacing between lines"),
4113 "tools.text", "line_spacing", 0,
4114 us, tbl, FALSE, NULL,
4115 -1000.0, 1000.0, 0.1, 0.1,
4116 sp_text_line_changed, 0.1, 1);
4117 gtk_widget_set_size_request (hb, 45, 0);
4118 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 3);
4119 }
4120 }
4122 {
4123 // horizontal kerning/vertical kerning units menu: create
4124 GtkWidget *us = sp_unit_selector_new(SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE);
4125 sp_unit_selector_setsize(us, AUX_OPTION_MENU_WIDTH, AUX_OPTION_MENU_HEIGHT);
4126 sp_unit_selector_set_unit(SP_UNIT_SELECTOR(us), desktop->namedview->doc_units);
4128 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4130 // horizontal kerning
4131 {
4132 {
4133 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_HORZ_KERN);
4134 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4135 gtk_container_add (GTK_CONTAINER (hb), image);
4136 gtk_widget_show(image);
4137 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4138 }
4140 {
4141 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Horizontal kerning"),
4142 "tools.text", "horizontal_kerning", 0,
4143 us, tbl, FALSE, NULL,
4144 -100.00, 100.00, 0.01, 0.1,
4145 sp_text_horiz_kern_changed);
4146 gtk_widget_set_size_request (hb, 45, 0);
4147 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4148 }
4149 }
4151 // vertical kerning
4152 {
4153 {
4154 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_VERT_KERN);
4155 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4156 gtk_container_add (GTK_CONTAINER (hb), image);
4157 gtk_widget_show(image);
4158 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4159 }
4161 {
4162 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Vertical kerning"),
4163 "tools.text", "vertical_kerning", 0,
4164 us, tbl, FALSE, NULL,
4165 -100.00, 100.00, 0.01, 0.1,
4166 sp_text_vert_kern_changed);
4167 gtk_widget_set_size_request (hb, 45, 0);
4168 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 5);
4169 }
4170 }
4172 // add the units menu
4173 gtk_widget_show(us);
4174 gtk_box_pack_start(GTK_BOX(tbl), us, FALSE, FALSE, 1);
4175 gtk_object_set_data(GTK_OBJECT(tbl), "units", us);
4176 }
4178 // letter rotation
4179 aux_toolbox_space(tbl, AUX_BETWEEN_BUTTON_GROUPS);
4180 {
4181 {
4182 GtkWidget *image = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_ROTATION);
4183 GtkWidget *hb = gtk_hbox_new(FALSE, 1);
4184 gtk_container_add (GTK_CONTAINER (hb), image);
4185 gtk_widget_show(image);
4186 gtk_box_pack_start (GTK_BOX (tbl), hb, FALSE, FALSE, 0);
4187 }
4188 {
4189 GtkWidget *hb = sp_tb_spinbutton(_(""), _("Letter rotation"),
4190 "tools.text", "letter_rotation", 0,
4191 us, tbl, FALSE, NULL,
4192 -180.0, 180.0, 0.1, 0.1,
4193 sp_text_letter_rotation_changed, 0.1, 1);
4194 gtk_widget_set_size_request (hb, 45, 0);
4195 gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, 6);
4196 }
4197 // rotation degree label
4198 {
4199 GtkWidget *label = gtk_widget_new (GTK_TYPE_LABEL, "label", "\302\260", "xalign", 0.0, NULL);
4200 gtk_box_pack_start(GTK_BOX(tbl), label, FALSE, FALSE, 0);
4201 }
4202 }
4204 // Remove Manual Kerns
4205 {
4206 GtkWidget *px = sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_STOCK_TEXT_REMOVE_KERNS);
4207 GtkWidget *button = gtk_button_new ();
4208 gtk_container_add (GTK_CONTAINER (button), px);
4209 gtk_widget_show(button);
4210 gtk_tooltips_set_tip (tt, button, _("Remove manual kerns"), NULL);
4211 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
4212 gtk_widget_set_sensitive(button, TRUE);
4213 gtk_box_pack_start (GTK_BOX (tbl), button, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
4214 }
4215 #endif
4217 gtk_widget_show_all (tbl);
4218 return tbl;
4220 } // end of sp_text_toolbox_new()
4222 }//<unnamed> namespace
4225 //#########################
4226 //## Connector Toolbox ##
4227 //#########################
4229 static void sp_connector_path_set_avoid(void)
4230 {
4231 cc_selection_set_avoid(true);
4232 }
4235 static void sp_connector_path_set_ignore(void)
4236 {
4237 cc_selection_set_avoid(false);
4238 }
4242 static void connector_spacing_changed(GtkAdjustment *adj, GtkWidget *tbl)
4243 {
4244 // quit if run by the _changed callbacks
4245 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4246 return;
4247 }
4249 SPDesktop *desktop = (SPDesktop *) gtk_object_get_data(GTK_OBJECT(tbl),
4250 "desktop");
4251 SPDocument *doc = sp_desktop_document(desktop);
4253 if (!sp_document_get_undo_sensitive(doc))
4254 {
4255 return;
4256 }
4258 // in turn, prevent callbacks from responding
4259 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE));
4261 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4263 sp_repr_set_css_double(repr, "inkscape:connector-spacing", adj->value);
4264 SP_OBJECT(desktop->namedview)->updateRepr();
4266 GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
4267 for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
4268 SPItem *item = reinterpret_cast<SPItem *>(iter->data);
4269 NR::Matrix m = NR::identity();
4270 avoid_item_move(&m, item);
4271 }
4273 if (items) {
4274 g_slist_free(items);
4275 }
4277 sp_document_done(doc, SP_VERB_CONTEXT_CONNECTOR,
4278 _("Change connector spacing"));
4280 g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE));
4282 spinbutton_defocus(GTK_OBJECT(tbl));
4283 }
4285 static void sp_connector_graph_layout(void)
4286 {
4287 if (!SP_ACTIVE_DESKTOP) return;
4289 // hack for clones, see comment in align-and-distribute.cpp
4290 int saved_compensation = prefs_get_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4291 prefs_set_int_attribute("options.clonecompensation", "value", SP_CLONE_COMPENSATION_UNMOVED);
4293 graphlayout(sp_desktop_selection(SP_ACTIVE_DESKTOP)->itemList());
4295 prefs_set_int_attribute("options.clonecompensation", "value", saved_compensation);
4297 sp_document_done(sp_desktop_document(SP_ACTIVE_DESKTOP), SP_VERB_DIALOG_ALIGN_DISTRIBUTE, _("Arrange connector network"));
4298 }
4300 static void
4301 sp_directed_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4302 {
4303 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4304 prefs_set_string_attribute("tools.connector", "directedlayout",
4305 "true");
4306 } else {
4307 prefs_set_string_attribute("tools.connector", "directedlayout",
4308 "false");
4309 }
4310 }
4311 static void
4312 sp_nooverlaps_graph_layout_toggled(GtkWidget *widget, GtkObject *tbl)
4313 {
4314 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
4315 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4316 "true");
4317 } else {
4318 prefs_set_string_attribute("tools.connector", "avoidoverlaplayout",
4319 "false");
4320 }
4321 }
4324 static void connector_length_changed(GtkAdjustment *adj, GtkWidget *tbl)
4325 {
4326 prefs_set_double_attribute("tools.connector", "length", adj->value);
4327 spinbutton_defocus(GTK_OBJECT(tbl));
4328 }
4330 static void connector_tb_event_attr_changed(Inkscape::XML::Node *repr,
4331 gchar const *name, gchar const *old_value, gchar const *new_value,
4332 bool is_interactive, gpointer data)
4333 {
4334 GtkWidget *tbl = GTK_WIDGET(data);
4336 if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
4337 return;
4338 }
4339 if (strcmp(name, "inkscape:connector-spacing") != 0) {
4340 return;
4341 }
4343 GtkAdjustment *adj = (GtkAdjustment*)
4344 gtk_object_get_data(GTK_OBJECT(tbl), "spacing");
4345 gdouble spacing = defaultConnSpacing;
4346 sp_repr_get_double(repr, "inkscape:connector-spacing", &spacing);
4348 gtk_adjustment_set_value(adj, spacing);
4349 }
4352 static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
4353 NULL, /* child_added */
4354 NULL, /* child_removed */
4355 connector_tb_event_attr_changed,
4356 NULL, /* content_changed */
4357 NULL /* order_changed */
4358 };
4361 static GtkWidget *
4362 sp_connector_toolbox_new(SPDesktop *desktop)
4363 {
4364 GtkTooltips *tt = gtk_tooltips_new();
4365 GtkWidget *tbl = gtk_hbox_new(FALSE, 0);
4367 gtk_object_set_data(GTK_OBJECT(tbl), "dtw", desktop->canvas);
4368 gtk_object_set_data(GTK_OBJECT(tbl), "desktop", desktop);
4370 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4371 AUX_BETWEEN_BUTTON_GROUPS);
4373 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4374 "connector_avoid", GTK_SIGNAL_FUNC(sp_connector_path_set_avoid),
4375 tt, _("Make connectors avoid selected objects"));
4377 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4378 "connector_ignore", GTK_SIGNAL_FUNC(sp_connector_path_set_ignore),
4379 tt, _("Make connectors ignore selected objects"));
4381 // interval
4382 gtk_box_pack_start(GTK_BOX(tbl), gtk_hbox_new(FALSE, 0), FALSE, FALSE,
4383 AUX_BETWEEN_BUTTON_GROUPS);
4385 // Spacing spinbox
4386 {
4387 GtkWidget *object_spacing = sp_tb_spinbutton(_("Spacing:"),
4388 _("The amount of space left around objects by auto-routing connectors"),
4389 "tools.connector", "spacing", 10, NULL, tbl, TRUE,
4390 "inkscape:connector-spacing", 0, 100, 1.0, 10.0,
4391 connector_spacing_changed, 1, 0);
4393 gtk_box_pack_start(GTK_BOX(tbl), object_spacing, FALSE, FALSE,
4394 AUX_SPACING);
4395 }
4396 // Graph (connector network) layout
4397 sp_toolbox_button_new(tbl, Inkscape::ICON_SIZE_SMALL_TOOLBAR,
4398 "graph_layout", GTK_SIGNAL_FUNC(sp_connector_graph_layout),
4399 tt, _("Nicely arrange selected connector network"));
4400 // Default connector length spinbox
4401 {
4402 GtkWidget *connector_length = sp_tb_spinbutton(_("Length:"),
4403 _("Ideal length for connectors when layout is applied"),
4404 "tools.connector", "length", 100, NULL, tbl, TRUE,
4405 "inkscape:connector-length", 10, 1000, 10.0, 100.0,
4406 connector_length_changed, 1, 0);
4408 gtk_box_pack_start(GTK_BOX(tbl), connector_length, FALSE, FALSE,
4409 AUX_SPACING);
4410 }
4411 gchar const *tbuttonstate;
4412 // Directed edges toggle button
4413 {
4414 GtkWidget *tbutton = gtk_toggle_button_new ();
4415 gtk_button_set_relief (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4416 gtk_container_add (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "directed_graph"));
4417 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4418 gtk_tooltips_set_tip(tt, tbutton, _("Make connectors with end-markers (arrows) point downwards"), NULL);
4420 gtk_box_pack_start (GTK_BOX (tbl), tbutton, FALSE, FALSE, 0);
4421 g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_directed_graph_layout_toggled), tbl);
4422 tbuttonstate = prefs_get_string_attribute("tools.connector", "directedlayout");
4423 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4424 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4425 }
4426 // Avoid overlaps toggle button
4427 {
4428 GtkWidget *tbutton = gtk_toggle_button_new ();
4429 gtk_button_set_relief (GTK_BUTTON (tbutton), GTK_RELIEF_NONE);
4430 gtk_container_add (GTK_CONTAINER (tbutton), sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, "remove_overlaps"));
4431 gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (tbutton), FALSE);
4432 gtk_tooltips_set_tip(tt, tbutton, _("Do not allow overlapping shapes"), NULL);
4434 gtk_box_pack_start (GTK_BOX (tbl), tbutton, FALSE, FALSE, 0);
4435 g_signal_connect(G_OBJECT(tbutton), "toggled", GTK_SIGNAL_FUNC(sp_nooverlaps_graph_layout_toggled), tbl);
4436 tbuttonstate = prefs_get_string_attribute("tools.connector", "avoidoverlaplayout");
4437 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(tbutton),
4438 (tbuttonstate && !strcmp(tbuttonstate, "true"))?TRUE:FALSE );
4439 }
4441 gtk_widget_show_all(tbl);
4442 sp_set_font_size_smaller (tbl);
4444 // Code to watch for changes to the connector-spacing attribute in
4445 // the XML.
4446 Inkscape::XML::Node *repr = SP_OBJECT_REPR(desktop->namedview);
4447 g_assert(repr != NULL);
4449 Inkscape::XML::Node *oldrepr = (Inkscape::XML::Node *)
4450 gtk_object_get_data(GTK_OBJECT(tbl), "repr");
4452 if (oldrepr) { // remove old listener
4453 sp_repr_remove_listener_by_data(oldrepr, tbl);
4454 Inkscape::GC::release(oldrepr);
4455 oldrepr = NULL;
4456 g_object_set_data(G_OBJECT(tbl), "repr", NULL);
4457 }
4459 if (repr) {
4460 g_object_set_data(G_OBJECT(tbl), "repr", repr);
4461 Inkscape::GC::anchor(repr);
4462 sp_repr_add_listener(repr, &connector_tb_repr_events, tbl);
4463 sp_repr_synthesize_events(repr, &connector_tb_repr_events, tbl);
4464 }
4466 return tbl;
4468 } // end of sp_connector_toolbox_new()
4470 static void paintbucket_channels_changed(EgeSelectOneAction* act, GObject* tbl)
4471 {
4472 gint channels = ege_select_one_action_get_active( act );
4473 flood_channels_set_channels( channels );
4474 }
4476 static void paintbucket_threshold_changed(GtkAdjustment *adj, GObject *tbl)
4477 {
4478 prefs_set_int_attribute("tools.paintbucket", "threshold", (gint)adj->value);
4479 }
4481 static void paintbucket_offset_changed(GtkAdjustment *adj, GObject *tbl)
4482 {
4483 UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data( tbl, "tracker" ));
4484 SPUnit const *unit = tracker->getActiveUnit();
4487 prefs_set_double_attribute("tools.paintbucket", "offset", (gdouble)sp_units_get_pixels(adj->value, *unit));
4488 }
4490 static void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
4491 {
4492 EgeAdjustmentAction* eact = 0;
4494 {
4495 GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
4497 GList* items = 0;
4498 gint count = 0;
4499 for ( items = flood_channels_dropdown_items_list(); items ; items = g_list_next(items) )
4500 {
4501 GtkTreeIter iter;
4502 gtk_list_store_append( model, &iter );
4503 gtk_list_store_set( model, &iter, 0, reinterpret_cast<gchar*>(items->data), 1, count, -1 );
4504 count++;
4505 }
4506 g_list_free( items );
4507 items = 0;
4508 EgeSelectOneAction* act1 = ege_select_one_action_new( "ChannelsAction", _("Fill by:"), _(""), NULL, GTK_TREE_MODEL(model) );
4509 ege_select_one_action_set_active( act1, prefs_get_int_attribute("tools.paintbucket", "channels", 0) );
4510 g_signal_connect( G_OBJECT(act1), "changed", G_CALLBACK(paintbucket_channels_changed), holder );
4511 gtk_action_group_add_action( mainActions, GTK_ACTION(act1) );
4512 }
4514 // Spacing spinbox
4515 {
4516 eact = create_adjustment_action(
4517 "ThresholdAction",
4518 _("Threshold:"),
4519 _("The maximum allowed difference between the clicked pixel and the neighboring pixels to be counted in the fill"),
4520 "tools.paintbucket", "threshold", 5, GTK_WIDGET(desktop->canvas), NULL, holder, TRUE,
4521 "inkscape:paintbucket-threshold", 0, 100.0, 1.0, 10.0,
4522 0, 0, 0,
4523 paintbucket_threshold_changed, 1, 0 );
4525 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4526 }
4528 // Create the units menu.
4529 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
4530 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
4531 g_object_set_data( holder, "tracker", tracker );
4532 {
4533 GtkAction* act = tracker->createAction( "PaintbucketUnitsAction", _("Units"), _("") );
4534 gtk_action_group_add_action( mainActions, act );
4535 }
4537 // Offset spinbox
4538 {
4539 eact = create_adjustment_action(
4540 "OffsetAction",
4541 _("Grow/shrink by:"),
4542 _("The amount to grow (positive) or shrink (negative) the created fill path"),
4543 "tools.paintbucket", "offset", 0, GTK_WIDGET(desktop->canvas), NULL/*us*/, holder, TRUE,
4544 "inkscape:paintbucket-offset", -1e6, 1e6, 0.1, 0.5,
4545 0, 0, 0,
4546 paintbucket_offset_changed, 1, 2);
4547 tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) );
4549 gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
4550 }
4551 }
4553 /*
4554 Local Variables:
4555 mode:c++
4556 c-file-style:"stroustrup"
4557 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
4558 indent-tabs-mode:nil
4559 fill-column:99
4560 End:
4561 */
4562 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :