Code

i18n. Context cleanup (context|string replaced with C_).
[inkscape.git] / src / widgets / select-toolbar.cpp
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));
104 static void
105 sp_selection_layout_widget_modify_selection(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data)
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     }
117 static void
118 sp_selection_layout_widget_change_selection(SPWidget *spw, Inkscape::Selection *selection, gpointer data)
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     }
137 static void
138 sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
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));
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 )
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;
295 // toggle button callbacks and updaters
297 static void toggle_stroke( GtkToggleAction* act, gpointer data )
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     }
310 static void toggle_corners( GtkToggleAction* act, gpointer data)
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     }
323 static void toggle_gradient( GtkToggleAction *act, gpointer data )
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     }
336 static void toggle_pattern( GtkToggleAction* act, gpointer data )
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     }
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     }
358 static void destroy_tracker( GObject* obj, gpointer /*user_data*/ )
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     }
367 static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
369     SPAction* targetAction = SP_ACTION(user_data);
370     if ( targetAction ) {
371         sp_action_perform( targetAction, NULL );
372     }
375 static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, Inkscape::IconSize size )
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;
390 void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
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     }
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 :