1 /*
2 * Selector aux toolbar
3 *
4 * Authors:
5 * Lauris Kaplinski <lauris@kaplinski.com>
6 * bulia byak <buliabyak@users.sf.net>
7 * Jon A. Cruz <jon@joncruz.org>
8 *
9 * Copyright (C) 2003-2005 authors
10 *
11 * Released under GNU GPL, read the file 'COPYING' for more information
12 */
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
18 #include <gtk/gtk.h>
19 #include <gtk/gtkaction.h>
21 #include "widgets/button.h"
22 #include "widgets/spw-utilities.h"
23 #include "widgets/widget-sizes.h"
24 #include "widgets/spinbutton-events.h"
25 #include "widgets/icon.h"
26 #include "widgets/sp-widget.h"
28 #include "preferences.h"
29 #include "selection-chemistry.h"
30 #include "document.h"
31 #include "inkscape.h"
32 #include "desktop-style.h"
33 #include "desktop.h"
34 #include "desktop-handles.h"
35 #include "sp-namedview.h"
36 #include "toolbox.h"
37 #include <glibmm/i18n.h>
38 #include "helper/unit-menu.h"
39 #include "helper/units.h"
40 #include "inkscape.h"
41 #include "verbs.h"
42 #include "selection.h"
43 #include "selection-chemistry.h"
44 #include "sp-item-transform.h"
45 #include "message-stack.h"
46 #include "display/sp-canvas.h"
47 #include "helper/unit-tracker.h"
48 #include "ege-adjustment-action.h"
49 #include "ege-output-action.h"
50 #include "ink-action.h"
51 #include <2geom/rect.h>
52 #include "ui/icon-names.h"
54 using Inkscape::UnitTracker;
56 static void
57 sp_selection_layout_widget_update(SPWidget *spw, Inkscape::Selection *sel)
58 {
59 if (g_object_get_data(G_OBJECT(spw), "update")) {
60 return;
61 }
63 g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE));
65 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
66 using Geom::X;
67 using Geom::Y;
68 if ( sel && !sel->isEmpty() ) {
69 int prefs_bbox = prefs->getInt("/tools/bounding_box", 0);
70 SPItem::BBoxType bbox_type = (prefs_bbox ==0)?
71 SPItem::APPROXIMATE_BBOX : SPItem::GEOMETRIC_BBOX;
72 Geom::OptRect const bbox(sel->bounds(bbox_type));
73 if ( bbox ) {
74 UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker"));
75 SPUnit const &unit = *tracker->getActiveUnit();
77 struct { char const *key; double val; } const keyval[] = {
78 { "X", bbox->min()[X] },
79 { "Y", bbox->min()[Y] },
80 { "width", bbox->dimensions()[X] },
81 { "height", bbox->dimensions()[Y] }
82 };
84 if (unit.base == SP_UNIT_DIMENSIONLESS) {
85 double const val = 1. / unit.unittobase;
86 for (unsigned i = 0; i < G_N_ELEMENTS(keyval); ++i) {
87 GtkAdjustment *a = (GtkAdjustment *) g_object_get_data(G_OBJECT(spw), keyval[i].key);
88 gtk_adjustment_set_value(a, val);
89 tracker->setFullVal( a, keyval[i].val );
90 }
91 } else {
92 for (unsigned i = 0; i < G_N_ELEMENTS(keyval); ++i) {
93 GtkAdjustment *a = (GtkAdjustment *) g_object_get_data(G_OBJECT(spw), keyval[i].key);
94 gtk_adjustment_set_value(a, sp_pixels_get_units(keyval[i].val, unit));
95 }
96 }
97 }
98 }
100 g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
101 }
104 static void
105 sp_selection_layout_widget_modify_selection(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data)
106 {
107 SPDesktop *desktop = (SPDesktop *) data;
108 if ((sp_desktop_selection(desktop) == selection) // only respond to changes in our desktop
109 && (flags & (SP_OBJECT_MODIFIED_FLAG |
110 SP_OBJECT_PARENT_MODIFIED_FLAG |
111 SP_OBJECT_CHILD_MODIFIED_FLAG )))
112 {
113 sp_selection_layout_widget_update(spw, selection);
114 }
115 }
117 static void
118 sp_selection_layout_widget_change_selection(SPWidget *spw, Inkscape::Selection *selection, gpointer data)
119 {
120 SPDesktop *desktop = (SPDesktop *) data;
121 if (sp_desktop_selection(desktop) == selection) { // only respond to changes in our desktop
122 gboolean setActive = (selection && !selection->isEmpty());
123 std::vector<GtkAction*> *contextActions = reinterpret_cast<std::vector<GtkAction*> *>(g_object_get_data(G_OBJECT(spw), "contextActions"));
124 if ( contextActions ) {
125 for ( std::vector<GtkAction*>::iterator iter = contextActions->begin();
126 iter != contextActions->end(); ++iter) {
127 if ( setActive != gtk_action_is_sensitive(*iter) ) {
128 gtk_action_set_sensitive( *iter, setActive );
129 }
130 }
131 }
133 sp_selection_layout_widget_update(spw, selection);
134 }
135 }
137 static void
138 sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
139 {
140 if (g_object_get_data(G_OBJECT(spw), "update")) {
141 return;
142 }
144 UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker"));
145 if ( !tracker || tracker->isUpdating() ) {
146 /*
147 * When only units are being changed, don't treat changes
148 * to adjuster values as object changes.
149 */
150 return;
151 }
152 g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE));
154 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
155 Inkscape::Selection *selection = sp_desktop_selection(desktop);
156 SPDocument *document = sp_desktop_document(desktop);
158 sp_document_ensure_up_to_date (document);
159 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
160 int prefs_bbox = prefs->getInt("/tools/bounding_box");
161 SPItem::BBoxType bbox_type = (prefs_bbox ==0)?
162 SPItem::APPROXIMATE_BBOX : SPItem::GEOMETRIC_BBOX;
163 Geom::OptRect bbox = selection->bounds(bbox_type);
165 if ( !bbox ) {
166 g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
167 return;
168 }
170 gdouble x0 = 0;
171 gdouble y0 = 0;
172 gdouble x1 = 0;
173 gdouble y1 = 0;
174 gdouble xrel = 0;
175 gdouble yrel = 0;
176 SPUnit const &unit = *tracker->getActiveUnit();
178 GtkAdjustment* a_x = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "X" ) );
179 GtkAdjustment* a_y = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "Y" ) );
180 GtkAdjustment* a_w = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "width" ) );
181 GtkAdjustment* a_h = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "height" ) );
183 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
184 x0 = sp_units_get_pixels (a_x->value, unit);
185 y0 = sp_units_get_pixels (a_y->value, unit);
186 x1 = x0 + sp_units_get_pixels (a_w->value, unit);
187 xrel = sp_units_get_pixels (a_w->value, unit) / bbox->dimensions()[Geom::X];
188 y1 = y0 + sp_units_get_pixels (a_h->value, unit);
189 yrel = sp_units_get_pixels (a_h->value, unit) / bbox->dimensions()[Geom::Y];
190 } else {
191 double const x0_propn = a_x->value * unit.unittobase;
192 x0 = bbox->min()[Geom::X] * x0_propn;
193 double const y0_propn = a_y->value * unit.unittobase;
194 y0 = y0_propn * bbox->min()[Geom::Y];
195 xrel = a_w->value * unit.unittobase;
196 x1 = x0 + xrel * bbox->dimensions()[Geom::X];
197 yrel = a_h->value * unit.unittobase;
198 y1 = y0 + yrel * bbox->dimensions()[Geom::Y];
199 }
201 // Keep proportions if lock is on
202 GtkToggleAction *lock = GTK_TOGGLE_ACTION( g_object_get_data(G_OBJECT(spw), "lock") );
203 if ( gtk_toggle_action_get_active(lock) ) {
204 if (adj == a_h) {
205 x1 = x0 + yrel * bbox->dimensions()[Geom::X];
206 } else if (adj == a_w) {
207 y1 = y0 + xrel * bbox->dimensions()[Geom::Y];
208 }
209 }
211 // scales and moves, in px
212 double mh = fabs(x0 - bbox->min()[Geom::X]);
213 double sh = fabs(x1 - bbox->max()[Geom::X]);
214 double mv = fabs(y0 - bbox->min()[Geom::Y]);
215 double sv = fabs(y1 - bbox->max()[Geom::Y]);
217 // unless the unit is %, convert the scales and moves to the unit
218 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
219 mh = sp_pixels_get_units (mh, unit);
220 sh = sp_pixels_get_units (sh, unit);
221 mv = sp_pixels_get_units (mv, unit);
222 sv = sp_pixels_get_units (sv, unit);
223 }
225 // do the action only if one of the scales/moves is greater than half the last significant
226 // digit in the spinbox (currently spinboxes have 3 fractional digits, so that makes 0.0005). If
227 // the value was changed by the user, the difference will be at least that much; otherwise it's
228 // just rounding difference between the spinbox value and actual value, so no action is
229 // performed
230 char const * const actionkey = ( mh > 5e-4 ? "selector:toolbar:move:horizontal" :
231 sh > 5e-4 ? "selector:toolbar:scale:horizontal" :
232 mv > 5e-4 ? "selector:toolbar:move:vertical" :
233 sv > 5e-4 ? "selector:toolbar:scale:vertical" : NULL );
235 if (actionkey != NULL) {
237 // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed
238 sp_canvas_force_full_redraw_after_interruptions(sp_desktop_canvas(desktop), 0);
240 gdouble strokewidth = stroke_average_width (selection->itemList());
241 int transform_stroke = prefs->getBool("/options/transform/stroke", true) ? 1 : 0;
243 Geom::Matrix scaler = get_scale_transform_with_stroke (*bbox, strokewidth, transform_stroke, x0, y0, x1, y1);
245 sp_selection_apply_affine(selection, scaler);
246 sp_document_maybe_done (document, actionkey, SP_VERB_CONTEXT_SELECT,
247 _("Transform by toolbar"));
249 // resume interruptibility
250 sp_canvas_end_forced_full_redraws(sp_desktop_canvas(desktop));
251 }
253 g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
254 }
256 static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
257 gchar const *label,
258 gchar const *shortLabel,
259 gchar const *data,
260 gdouble lower,
261 GtkWidget* focusTarget,
262 UnitTracker* tracker,
263 GtkWidget* spw,
264 gchar const *tooltip,
265 gboolean altx )
266 {
267 GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, lower, 1e6, SPIN_STEP, SPIN_PAGE_STEP, 0 ) );
268 if (tracker) {
269 tracker->addAdjustment(adj);
270 }
271 if ( spw ) {
272 g_object_set_data( G_OBJECT(spw), data, adj );
273 }
275 EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, Q_(label), tooltip, 0, SPIN_STEP, 3 );
276 if ( shortLabel ) {
277 g_object_set( act, "short_label", Q_(shortLabel), NULL );
278 }
280 gtk_signal_connect( GTK_OBJECT(adj), "value_changed", GTK_SIGNAL_FUNC(sp_object_layout_any_value_changed), spw );
281 if ( focusTarget ) {
282 ege_adjustment_action_set_focuswidget( act, focusTarget );
283 }
285 if ( altx ) { // this spinbutton will be activated by alt-x
286 g_object_set( G_OBJECT(act), "self-id", "altx", NULL );
287 }
289 // Using a cast just to make sure we pass in the right kind of function pointer
290 g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
292 return act;
293 }
295 // toggle button callbacks and updaters
297 static void toggle_stroke( GtkToggleAction* act, gpointer data )
298 {
299 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
300 gboolean active = gtk_toggle_action_get_active(act);
301 prefs->setBool("/options/transform/stroke", active);
302 SPDesktop *desktop = (SPDesktop *)data;
303 if ( active ) {
304 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>stroke width</b> is <b>scaled</b> when objects are scaled."));
305 } else {
306 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>stroke width</b> is <b>not scaled</b> when objects are scaled."));
307 }
308 }
310 static void toggle_corners( GtkToggleAction* act, gpointer data)
311 {
312 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
313 gboolean active = gtk_toggle_action_get_active(act);
314 prefs->setBool("/options/transform/rectcorners", active);
315 SPDesktop *desktop = (SPDesktop *)data;
316 if ( active ) {
317 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>rounded rectangle corners</b> are <b>scaled</b> when rectangles are scaled."));
318 } else {
319 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>rounded rectangle corners</b> are <b>not scaled</b> when rectangles are scaled."));
320 }
321 }
323 static void toggle_gradient( GtkToggleAction *act, gpointer data )
324 {
325 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
326 gboolean active = gtk_toggle_action_get_active(act);
327 prefs->setBool("/options/transform/gradient", active);
328 SPDesktop *desktop = (SPDesktop *)data;
329 if ( active ) {
330 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>gradients</b> are <b>transformed</b> along with their objects when those are transformed (moved, scaled, rotated, or skewed)."));
331 } else {
332 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>gradients</b> remain <b>fixed</b> when objects are transformed (moved, scaled, rotated, or skewed)."));
333 }
334 }
336 static void toggle_pattern( GtkToggleAction* act, gpointer data )
337 {
338 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
339 gboolean active = gtk_toggle_action_get_active(act);
340 prefs->setInt("/options/transform/pattern", active);
341 SPDesktop *desktop = (SPDesktop *)data;
342 if ( active ) {
343 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>patterns</b> are <b>transformed</b> along with their objects when those are transformed (moved, scaled, rotated, or skewed)."));
344 } else {
345 desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>patterns</b> remain <b>fixed</b> when objects are transformed (moved, scaled, rotated, or skewed)."));
346 }
347 }
349 static void toggle_lock( GtkToggleAction *act, gpointer /*data*/ ) {
350 gboolean active = gtk_toggle_action_get_active( act );
351 if ( active ) {
352 g_object_set( G_OBJECT(act), "iconId", INKSCAPE_ICON_OBJECT_LOCKED, NULL );
353 } else {
354 g_object_set( G_OBJECT(act), "iconId", INKSCAPE_ICON_OBJECT_UNLOCKED, NULL );
355 }
356 }
358 static void destroy_tracker( GObject* obj, gpointer /*user_data*/ )
359 {
360 UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(obj, "tracker"));
361 if ( tracker ) {
362 delete tracker;
363 g_object_set_data( obj, "tracker", 0 );
364 }
365 }
367 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
368 {
369 SPAction* targetAction = SP_ACTION(user_data);
370 if ( targetAction ) {
371 sp_action_perform( targetAction, NULL );
372 }
373 }
375 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
376 {
377 GtkAction* act = 0;
379 SPAction* targetAction = verb->get_action(view);
380 InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
381 act = GTK_ACTION(inky);
383 g_signal_connect( G_OBJECT(inky), "activate", GTK_SIGNAL_FUNC(trigger_sp_action), targetAction );
385 Inkscape::queueIconPrerender( verb->get_image(), size );
387 return act;
388 }
390 void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
391 {
392 Inkscape::UI::View::View *view = desktop;
393 Inkscape::IconSize secondarySize = Inkscape::UI::ToolboxFactory::prefToSize("/toolbox/secondary", 1);
394 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
396 GtkAction* act = 0;
398 GtkActionGroup* selectionActions = mainActions; // temporary
399 std::vector<GtkAction*>* contextActions = new std::vector<GtkAction*>();
401 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_EDIT_SELECT_ALL), view, secondarySize );
402 gtk_action_group_add_action( selectionActions, act );
403 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS), view, secondarySize );
404 gtk_action_group_add_action( selectionActions, act );
405 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_EDIT_DESELECT), view, secondarySize );
406 gtk_action_group_add_action( selectionActions, act );
407 contextActions->push_back( act );
409 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_ROTATE_90_CCW), view, secondarySize );
410 gtk_action_group_add_action( selectionActions, act );
411 contextActions->push_back( act );
412 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_ROTATE_90_CW), view, secondarySize );
413 gtk_action_group_add_action( selectionActions, act );
414 contextActions->push_back( act );
415 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_FLIP_HORIZONTAL), view, secondarySize );
416 gtk_action_group_add_action( selectionActions, act );
417 contextActions->push_back( act );
418 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_FLIP_VERTICAL), view, secondarySize );
419 gtk_action_group_add_action( selectionActions, act );
420 contextActions->push_back( act );
422 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_TO_BACK), view, secondarySize );
423 gtk_action_group_add_action( selectionActions, act );
424 contextActions->push_back( act );
425 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_LOWER), view, secondarySize );
426 gtk_action_group_add_action( selectionActions, act );
427 contextActions->push_back( act );
428 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_RAISE), view, secondarySize );
429 gtk_action_group_add_action( selectionActions, act );
430 contextActions->push_back( act );
431 act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_TO_FRONT), view, secondarySize );
432 gtk_action_group_add_action( selectionActions, act );
433 contextActions->push_back( act );
435 // Create the parent widget for x y w h tracker.
436 GtkWidget *spw = sp_widget_new_global(INKSCAPE);
438 // Remember the desktop's canvas widget, to be used for defocusing.
439 g_object_set_data(G_OBJECT(spw), "dtw", sp_desktop_canvas(desktop));
441 // The vb frame holds all other widgets and is used to set sensitivity depending on selection state.
442 GtkWidget *vb = gtk_hbox_new(FALSE, 0);
443 gtk_widget_show(vb);
444 gtk_container_add(GTK_CONTAINER(spw), vb);
446 // Create the units menu.
447 UnitTracker* tracker = new UnitTracker( SP_UNIT_ABSOLUTE | SP_UNIT_DEVICE );
448 tracker->addUnit( SP_UNIT_PERCENT, 0 );
449 tracker->setActiveUnit( sp_desktop_namedview(desktop)->doc_units );
451 g_object_set_data( G_OBJECT(spw), "tracker", tracker );
452 g_signal_connect( G_OBJECT(spw), "destroy", G_CALLBACK(destroy_tracker), spw );
454 EgeAdjustmentAction* eact = 0;
456 // four spinbuttons
458 eact = create_adjustment_action( "XAction", C_("Select toolbar", "X position"), C_("Select toolbar", "X:"), "X",
459 -1e6, GTK_WIDGET(desktop->canvas), tracker, spw,
460 _("Horizontal coordinate of selection"), TRUE );
461 gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
462 contextActions->push_back( GTK_ACTION(eact) );
464 eact = create_adjustment_action( "YAction", C_("Select toolbar", "Y position"), C_("Select toolbar", "Y:"), "Y",
465 -1e6, GTK_WIDGET(desktop->canvas), tracker, spw,
466 _("Vertical coordinate of selection"), FALSE );
467 gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
468 contextActions->push_back( GTK_ACTION(eact) );
470 eact = create_adjustment_action( "WidthAction", C_("Select toolbar", "Width"), C_("Select toolbar", "W:"), "width",
471 1e-3, GTK_WIDGET(desktop->canvas), tracker, spw,
472 _("Width of selection"), FALSE );
473 gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
474 contextActions->push_back( GTK_ACTION(eact) );
476 // lock toggle
477 {
478 InkToggleAction* itact = ink_toggle_action_new( "LockAction",
479 _("Lock width and height"),
480 _("When locked, change both width and height by the same proportion"),
481 INKSCAPE_ICON_OBJECT_UNLOCKED,
482 Inkscape::ICON_SIZE_DECORATION );
483 g_object_set( itact, "short_label", "Lock", NULL );
484 g_object_set_data( G_OBJECT(spw), "lock", itact );
485 g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_lock), desktop) ;
486 gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
487 }
489 eact = create_adjustment_action( "HeightAction", C_("Select toolbar", "Height"), C_("Select toolbar", "H:"), "height",
490 1e-3, GTK_WIDGET(desktop->canvas), tracker, spw,
491 _("Height of selection"), FALSE );
492 gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
493 contextActions->push_back( GTK_ACTION(eact) );
495 // Add the units menu.
496 act = tracker->createAction( "UnitsAction", _("Units"), ("") );
497 gtk_action_group_add_action( selectionActions, act );
499 g_object_set_data( G_OBJECT(spw), "selectionActions", selectionActions );
500 g_object_set_data( G_OBJECT(spw), "contextActions", contextActions );
502 // Force update when selection changes.
503 gtk_signal_connect(GTK_OBJECT(spw), "modify_selection", GTK_SIGNAL_FUNC(sp_selection_layout_widget_modify_selection), desktop);
504 gtk_signal_connect(GTK_OBJECT(spw), "change_selection", GTK_SIGNAL_FUNC(sp_selection_layout_widget_change_selection), desktop);
506 // Update now.
507 sp_selection_layout_widget_update(SP_WIDGET(spw), SP_ACTIVE_DESKTOP ? sp_desktop_selection(SP_ACTIVE_DESKTOP) : NULL);
509 for ( std::vector<GtkAction*>::iterator iter = contextActions->begin();
510 iter != contextActions->end(); ++iter) {
511 if ( gtk_action_is_sensitive(*iter) ) {
512 gtk_action_set_sensitive( *iter, FALSE );
513 }
514 }
516 // Insert spw into the toolbar.
517 if ( GTK_IS_BOX(holder) ) {
518 gtk_box_pack_start(GTK_BOX(holder), spw, FALSE, FALSE, 0);
519 } else if ( GTK_IS_TOOLBAR(holder) ) {
520 gtk_toolbar_append_widget( GTK_TOOLBAR(holder), spw, "Text", "priv" );
521 } else {
522 g_warning("Unexpected holder type");
523 }
525 // "Transform with object" buttons
527 {
528 EgeOutputAction* act = ege_output_action_new( "transform_affect_label", _("Affect:"), _("Control whether or not to scale stroke widths, scale rectangle corners, transform gradient fills, and transform pattern fills with the object"), 0 );
529 ege_output_action_set_use_markup( act, TRUE );
530 g_object_set( act, "visible-overflown", FALSE, NULL );
531 gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
532 }
534 {
535 InkToggleAction* itact = ink_toggle_action_new( "transform_stroke",
536 _("Scale stroke width"),
537 _("When scaling objects, scale the stroke width by the same proportion"),
538 INKSCAPE_ICON_TRANSFORM_AFFECT_STROKE,
539 Inkscape::ICON_SIZE_DECORATION );
540 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/stroke", true) );
541 g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_stroke), desktop) ;
542 gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
543 }
545 {
546 InkToggleAction* itact = ink_toggle_action_new( "transform_corners",
547 _("Scale rounded corners"),
548 _("When scaling rectangles, scale the radii of rounded corners"),
549 INKSCAPE_ICON_TRANSFORM_AFFECT_ROUNDED_CORNERS,
550 Inkscape::ICON_SIZE_DECORATION );
551 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/rectcorners", true) );
552 g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_corners), desktop) ;
553 gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
554 }
556 {
557 InkToggleAction* itact = ink_toggle_action_new( "transform_gradient",
558 _("Move gradients"),
559 _("Move gradients (in fill or stroke) along with the objects"),
560 INKSCAPE_ICON_TRANSFORM_AFFECT_GRADIENT,
561 Inkscape::ICON_SIZE_DECORATION );
562 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/gradient", true) );
563 g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_gradient), desktop) ;
564 gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
565 }
567 {
568 InkToggleAction* itact = ink_toggle_action_new( "transform_pattern",
569 _("Move patterns"),
570 _("Move patterns (in fill or stroke) along with the objects"),
571 INKSCAPE_ICON_TRANSFORM_AFFECT_PATTERN,
572 Inkscape::ICON_SIZE_DECORATION );
573 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/pattern", true) );
574 g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_pattern), desktop) ;
575 gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
576 }
577 }
580 /*
581 Local Variables:
582 mode:c++
583 c-file-style:"stroustrup"
584 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
585 indent-tabs-mode:nil
586 fill-column:99
587 End:
588 */
589 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :