diff options
| author | Alexander Valavanis <valavanisalex@gmail.com> | 2019-01-19 13:58:46 +0000 |
|---|---|---|
| committer | Alexander Valavanis <valavanisalex@gmail.com> | 2019-01-19 13:58:46 +0000 |
| commit | e77e650354daef5ced80adddf6d5a334bb6216d3 (patch) | |
| tree | ac1237a3194056ac457b5a9a7468b0d61c3a7335 /src/ui/toolbar/select-toolbar.cpp | |
| parent | Merge branch 'master' of gitlab.com:inkscape/inkscape (diff) | |
| download | inkscape-e77e650354daef5ced80adddf6d5a334bb6216d3.tar.gz inkscape-e77e650354daef5ced80adddf6d5a334bb6216d3.zip | |
derive all toolbars from Inkscape::Toolbar
Diffstat (limited to 'src/ui/toolbar/select-toolbar.cpp')
| -rw-r--r-- | src/ui/toolbar/select-toolbar.cpp | 607 |
1 files changed, 301 insertions, 306 deletions
diff --git a/src/ui/toolbar/select-toolbar.cpp b/src/ui/toolbar/select-toolbar.cpp index 0e1ad9c1b..604b185b7 100644 --- a/src/ui/toolbar/select-toolbar.cpp +++ b/src/ui/toolbar/select-toolbar.cpp @@ -44,7 +44,6 @@ #include "ui/widget/unit-tracker.h" #include "widgets/ege-adjustment-action.h" -#include "widgets/sp-widget.h" #include "widgets/widget-sizes.h" using Inkscape::UI::Widget::UnitTracker; @@ -53,219 +52,7 @@ using Inkscape::Util::Quantity; using Inkscape::DocumentUndo; using Inkscape::Util::unit_table; -static void -sp_selection_layout_widget_update(SPWidget *spw, Inkscape::Selection *sel) -{ - if (g_object_get_data(G_OBJECT(spw), "update")) { - return; - } - - g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE)); - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - using Geom::X; - using Geom::Y; - if ( sel && !sel->isEmpty() ) { - int prefs_bbox = prefs->getInt("/tools/bounding_box", 0); - SPItem::BBoxType bbox_type = (prefs_bbox ==0)? - SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; - Geom::OptRect const bbox(sel->bounds(bbox_type)); - if ( bbox ) { - UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker")); - Unit const *unit = tracker->getActiveUnit(); - g_return_if_fail(unit != nullptr); - struct { char const *key; double val; } const keyval[] = { - { "X", bbox->min()[X] }, - { "Y", bbox->min()[Y] }, - { "width", bbox->dimensions()[X] }, - { "height", bbox->dimensions()[Y] } - }; - - if (unit->type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) { - double const val = unit->factor * 100; - for (auto i : keyval) { - GtkAdjustment *a = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(spw), i.key)); - gtk_adjustment_set_value(a, val); - tracker->setFullVal( a, i.val ); - } - } else { - for (auto i : keyval) { - GtkAdjustment *a = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(spw), i.key)); - gtk_adjustment_set_value(a, Quantity::convert(i.val, "px", unit)); - } - } - } - } - - g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE)); -} - - -static void -sp_selection_layout_widget_modify_selection(SPWidget *spw, Inkscape::Selection *selection, guint flags, gpointer data) -{ - SPDesktop *desktop = static_cast<SPDesktop *>(data); - if ((desktop->getSelection() == selection) // only respond to changes in our desktop - && (flags & (SP_OBJECT_MODIFIED_FLAG | - SP_OBJECT_PARENT_MODIFIED_FLAG | - SP_OBJECT_CHILD_MODIFIED_FLAG ))) - { - sp_selection_layout_widget_update(spw, selection); - } -} - -static void -sp_selection_layout_widget_change_selection(SPWidget *spw, Inkscape::Selection *selection, gpointer data) -{ - SPDesktop *desktop = static_cast<SPDesktop *>(data); - if (desktop->getSelection() == selection) { // only respond to changes in our desktop - gboolean setActive = (selection && !selection->isEmpty()); - std::vector<GtkAction*> *contextActions = reinterpret_cast<std::vector<GtkAction*> *>(g_object_get_data(G_OBJECT(spw), "contextActions")); - if ( contextActions ) { - for (auto & contextAction : *contextActions) { - if ( setActive != gtk_action_is_sensitive(contextAction) ) { - gtk_action_set_sensitive( contextAction, setActive ); - } - } - } - - sp_selection_layout_widget_update(spw, selection); - } -} - -static void -sp_object_layout_any_value_changed(GtkAdjustment *adj, GObject *tbl) -{ - if (g_object_get_data(tbl, "update")) { - return; - } - - UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); - if ( !tracker || tracker->isUpdating() ) { - /* - * When only units are being changed, don't treat changes - * to adjuster values as object changes. - */ - return; - } - g_object_set_data(tbl, "update", GINT_TO_POINTER(TRUE)); - - SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Selection *selection = desktop->getSelection(); - SPDocument *document = desktop->getDocument(); - - document->ensureUpToDate (); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - Geom::OptRect bbox_vis = selection->visualBounds(); - Geom::OptRect bbox_geom = selection->geometricBounds(); - - int prefs_bbox = prefs->getInt("/tools/bounding_box"); - SPItem::BBoxType bbox_type = (prefs_bbox == 0)? - SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; - Geom::OptRect bbox_user = selection->bounds(bbox_type); - - if ( !bbox_user ) { - g_object_set_data(tbl, "update", GINT_TO_POINTER(FALSE)); - return; - } - - gdouble x0 = 0; - gdouble y0 = 0; - gdouble x1 = 0; - gdouble y1 = 0; - gdouble xrel = 0; - gdouble yrel = 0; - Unit const *unit = tracker->getActiveUnit(); - g_return_if_fail(unit != nullptr); - - GtkAdjustment* a_x = GTK_ADJUSTMENT( g_object_get_data( tbl, "X" ) ); - GtkAdjustment* a_y = GTK_ADJUSTMENT( g_object_get_data( tbl, "Y" ) ); - GtkAdjustment* a_w = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) ); - GtkAdjustment* a_h = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) ); - - if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { - x0 = Quantity::convert(gtk_adjustment_get_value(a_x), unit, "px"); - y0 = Quantity::convert(gtk_adjustment_get_value(a_y), unit, "px"); - x1 = x0 + Quantity::convert(gtk_adjustment_get_value(a_w), unit, "px"); - xrel = Quantity::convert(gtk_adjustment_get_value(a_w), unit, "px") / bbox_user->dimensions()[Geom::X]; - y1 = y0 + Quantity::convert(gtk_adjustment_get_value(a_h), unit, "px");; - yrel = Quantity::convert(gtk_adjustment_get_value(a_h), unit, "px") / bbox_user->dimensions()[Geom::Y]; - } else { - double const x0_propn = gtk_adjustment_get_value (a_x) / 100 / unit->factor; - x0 = bbox_user->min()[Geom::X] * x0_propn; - double const y0_propn = gtk_adjustment_get_value (a_y) / 100 / unit->factor; - y0 = y0_propn * bbox_user->min()[Geom::Y]; - xrel = gtk_adjustment_get_value (a_w) / (100 / unit->factor); - x1 = x0 + xrel * bbox_user->dimensions()[Geom::X]; - yrel = gtk_adjustment_get_value (a_h) / (100 / unit->factor); - y1 = y0 + yrel * bbox_user->dimensions()[Geom::Y]; - } - - // Keep proportions if lock is on - GtkToggleAction *lock = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "lock") ); - if ( gtk_toggle_action_get_active(lock) ) { - if (adj == a_h) { - x1 = x0 + yrel * bbox_user->dimensions()[Geom::X]; - } else if (adj == a_w) { - y1 = y0 + xrel * bbox_user->dimensions()[Geom::Y]; - } - } - - // scales and moves, in px - double mh = fabs(x0 - bbox_user->min()[Geom::X]); - double sh = fabs(x1 - bbox_user->max()[Geom::X]); - double mv = fabs(y0 - bbox_user->min()[Geom::Y]); - double sv = fabs(y1 - bbox_user->max()[Geom::Y]); - - // unless the unit is %, convert the scales and moves to the unit - if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { - mh = Quantity::convert(mh, "px", unit); - sh = Quantity::convert(sh, "px", unit); - mv = Quantity::convert(mv, "px", unit); - sv = Quantity::convert(sv, "px", unit); - } - - // do the action only if one of the scales/moves is greater than half the last significant - // digit in the spinbox (currently spinboxes have 3 fractional digits, so that makes 0.0005). If - // the value was changed by the user, the difference will be at least that much; otherwise it's - // just rounding difference between the spinbox value and actual value, so no action is - // performed - char const * const actionkey = ( mh > 5e-4 ? "selector:toolbar:move:horizontal" : - sh > 5e-4 ? "selector:toolbar:scale:horizontal" : - mv > 5e-4 ? "selector:toolbar:move:vertical" : - sv > 5e-4 ? "selector:toolbar:scale:vertical" : nullptr ); - - if (actionkey != nullptr) { - - // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed - desktop->getCanvas()->forceFullRedrawAfterInterruptions(0); - - bool transform_stroke = prefs->getBool("/options/transform/stroke", true); - bool preserve = prefs->getBool("/options/preservetransform/value", false); - - Geom::Affine scaler; - if (bbox_type == SPItem::VISUAL_BBOX) { - scaler = get_scale_transform_for_variable_stroke (*bbox_vis, *bbox_geom, transform_stroke, preserve, x0, y0, x1, y1); - } else { - // 1) We could have use the newer get_scale_transform_for_variable_stroke() here, but to avoid regressions - // we'll just use the old get_scale_transform_for_uniform_stroke() for now. - // 2) get_scale_transform_for_uniform_stroke() is intended for visual bounding boxes, not geometrical ones! - // we'll trick it into using a geometric bounding box though, by setting the stroke width to zero - scaler = get_scale_transform_for_uniform_stroke (*bbox_geom, 0, 0, false, false, x0, y0, x1, y1); - } - - selection->applyAffine(scaler); - DocumentUndo::maybeDone(document, actionkey, SP_VERB_CONTEXT_SELECT, - _("Transform by toolbar")); - - // resume interruptibility - desktop->getCanvas()->endForcedFullRedraws(); - } - - g_object_set_data(tbl, "update", GINT_TO_POINTER(FALSE)); -} // toggle button callbacks and updaters @@ -330,15 +117,6 @@ static void toggle_lock( GtkToggleAction *act, gpointer /*data*/ ) { } } -static void destroy_tracker( GObject* obj, gpointer /*user_data*/ ) -{ - UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(obj, "tracker")); - if ( tracker ) { - delete tracker; - g_object_set_data( obj, "tracker", nullptr ); - } -} - static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data ) { SPAction* targetAction = SP_ACTION(user_data); @@ -360,70 +138,78 @@ static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::Vi return act; } -void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +namespace Inkscape { +namespace UI { +namespace Toolbar { + +SelectToolbar::SelectToolbar(SPDesktop *desktop) : + Toolbar(desktop), + _context_actions(new std::vector<GtkAction*>()), + _tracker(new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR)), + _update(false) +{} + +SelectToolbar::~SelectToolbar() +{ + delete _tracker; +} + +GtkWidget * +SelectToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) { + auto holder = new SelectToolbar(desktop); + Inkscape::UI::View::View *view = desktop; GtkIconSize secondarySize = Inkscape::UI::ToolboxFactory::prefToSize("/toolbox/secondary", 1); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); GtkAction* act = nullptr; - GtkActionGroup* selectionActions = mainActions; // temporary - std::vector<GtkAction*>* contextActions = new std::vector<GtkAction*>(); + holder->_selection_actions = mainActions; // temporary act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_EDIT_SELECT_ALL), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); + gtk_action_group_add_action( holder->_selection_actions, act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); + gtk_action_group_add_action( holder->_selection_actions, act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_EDIT_DESELECT), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_ROTATE_90_CCW), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_ROTATE_90_CW), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_FLIP_HORIZONTAL), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_OBJECT_FLIP_VERTICAL), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_TO_BACK), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_LOWER), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_RAISE), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_SELECTION_TO_FRONT), view, secondarySize ); - gtk_action_group_add_action( selectionActions, act ); - contextActions->push_back( act ); + gtk_action_group_add_action( holder->_selection_actions, act ); + holder->_context_actions->push_back( act ); // Create the parent widget for x y w h tracker. - GtkWidget *spw = sp_widget_new_global(); - - // Remember the desktop's canvas widget, to be used for defocusing. - g_object_set_data(G_OBJECT(spw), "dtw", desktop->getCanvas()); - // The vb frame holds all other widgets and is used to set sensitivity depending on selection state. auto vb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_set_homogeneous(GTK_BOX(vb), FALSE); gtk_widget_show(vb); - gtk_container_add(GTK_CONTAINER(spw), vb); // Create the units menu. - UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); - tracker->addUnit(unit_table.getUnit("%")); - tracker->setActiveUnit( desktop->getNamedView()->display_units ); - - g_object_set_data( G_OBJECT(spw), "tracker", tracker ); - g_signal_connect( G_OBJECT(spw), "destroy", G_CALLBACK(destroy_tracker), spw ); + holder->_tracker->addUnit(unit_table.getUnit("%")); + holder->_tracker->setActiveUnit( desktop->getNamedView()->display_units ); EgeAdjustmentAction* eact = nullptr; @@ -437,16 +223,18 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb "/tools/select/X", /* path */ 0.0, /* def(default) */ GTK_WIDGET(desktop->canvas), /* focusTarget */ - G_OBJECT(spw), /* dataKludge */ + nullptr, /* dataKludge */ TRUE, "altx", /* altx, altx_mark */ -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */ - nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */ - sp_object_layout_any_value_changed, /* callback */ - tracker, /* unit_tracker */ + nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */ + nullptr, /* callback */ + holder->_tracker, /* unit_tracker */ SPIN_STEP, 3, 1); /* climb, digits, factor */ - gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); - contextActions->push_back( GTK_ACTION(eact) ); + holder->_adj_x = Glib::wrap(GTK_ADJUSTMENT(ege_adjustment_action_get_adjustment(eact))); + holder->_adj_x->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*holder, &SelectToolbar::any_value_changed), holder->_adj_x)); + gtk_action_group_add_action( holder->_selection_actions, GTK_ACTION(eact) ); + holder->_context_actions->push_back( GTK_ACTION(eact) ); eact = create_adjustment_action( "YAction", /* name */ @@ -456,16 +244,18 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb "/tools/select/Y", /* path */ 0.0, /* def(default) */ GTK_WIDGET(desktop->canvas), /* focusTarget */ - G_OBJECT(spw), /* dataKludge */ + nullptr, /* dataKludge */ TRUE, "altx", /* altx, altx_mark */ -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */ nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */ - sp_object_layout_any_value_changed, /* callback */ - tracker, /* unit_tracker */ + nullptr, /* callback */ + holder->_tracker, /* unit_tracker */ SPIN_STEP, 3, 1); /* climb, digits, factor */ - gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); - contextActions->push_back( GTK_ACTION(eact) ); + holder->_adj_y = Glib::wrap(GTK_ADJUSTMENT(ege_adjustment_action_get_adjustment(eact))); + holder->_adj_y->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*holder, &SelectToolbar::any_value_changed), holder->_adj_y)); + gtk_action_group_add_action( holder->_selection_actions, GTK_ACTION(eact) ); + holder->_context_actions->push_back( GTK_ACTION(eact) ); eact = create_adjustment_action( "WidthAction", /* name */ @@ -475,28 +265,29 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb "/tools/select/width", /* path */ 0.0, /* def(default) */ GTK_WIDGET(desktop->canvas), /* focusTarget */ - G_OBJECT(spw), /* dataKludge */ + nullptr, /* dataKludge */ TRUE, "altx", /* altx, altx_mark */ 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */ nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */ - sp_object_layout_any_value_changed, /* callback */ - tracker, /* unit_tracker */ + nullptr, /* callback */ + holder->_tracker, /* unit_tracker */ SPIN_STEP, 3, 1); /* climb, digits, factor */ - gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); - contextActions->push_back( GTK_ACTION(eact) ); + holder->_adj_w = Glib::wrap(GTK_ADJUSTMENT(ege_adjustment_action_get_adjustment(eact))); + holder->_adj_w->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*holder, &SelectToolbar::any_value_changed), holder->_adj_w)); + gtk_action_group_add_action( holder->_selection_actions, GTK_ACTION(eact) ); + holder->_context_actions->push_back( GTK_ACTION(eact) ); // lock toggle { - InkToggleAction* itact = ink_toggle_action_new( "LockAction", - _("Lock width and height"), - _("When locked, change both width and height by the same proportion"), - INKSCAPE_ICON("object-unlocked"), - GTK_ICON_SIZE_MENU ); - g_object_set( itact, "short_label", "Lock", NULL ); - g_object_set_data( G_OBJECT(spw), "lock", itact ); - g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_lock), desktop) ; - gtk_action_group_add_action( mainActions, GTK_ACTION(itact) ); + holder->_lock = GTK_TOGGLE_ACTION(ink_toggle_action_new( "LockAction", + _("Lock width and height"), + _("When locked, change both width and height by the same proportion"), + INKSCAPE_ICON("object-unlocked"), + GTK_ICON_SIZE_MENU )); + gtk_action_set_short_label( GTK_ACTION(holder->_lock), "Lock" ); + g_signal_connect_after( G_OBJECT(holder->_lock), "toggled", G_CALLBACK(toggle_lock), desktop) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(holder->_lock) ); } eact = create_adjustment_action( @@ -507,50 +298,44 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb "/tools/select/height", /* path */ 0.0, /* def(default) */ GTK_WIDGET(desktop->canvas), /* focusTarget */ - G_OBJECT(spw), /* dataKludge */ + nullptr, /* dataKludge */ TRUE, "altx", /* altx, altx_mark */ 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */ nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */ - sp_object_layout_any_value_changed, /* callback */ - tracker, /* unit_tracker */ + nullptr, /* callback */ + holder->_tracker, /* unit_tracker */ SPIN_STEP, 3, 1); /* climb, digits, factor */ - gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); - contextActions->push_back( GTK_ACTION(eact) ); + holder->_adj_h = Glib::wrap(GTK_ADJUSTMENT(ege_adjustment_action_get_adjustment(eact))); + holder->_adj_h->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*holder, &SelectToolbar::any_value_changed), holder->_adj_h)); + gtk_action_group_add_action( holder->_selection_actions, GTK_ACTION(eact) ); + holder->_context_actions->push_back( GTK_ACTION(eact) ); // Add the units menu. { - InkSelectOneAction* act = tracker->createAction( "UnitsAction", _("Units"), ("") ); - gtk_action_group_add_action( selectionActions, act->gobj() ); + InkSelectOneAction* act = holder->_tracker->createAction( "UnitsAction", _("Units"), ("") ); + gtk_action_group_add_action( holder->_selection_actions, act->gobj() ); } - g_object_set_data( G_OBJECT(spw), "selectionActions", selectionActions ); - g_object_set_data( G_OBJECT(spw), "contextActions", contextActions ); - // Force update when selection changes. - g_signal_connect(G_OBJECT(spw), "modify_selection", G_CALLBACK(sp_selection_layout_widget_modify_selection), desktop); - g_signal_connect(G_OBJECT(spw), "change_selection", G_CALLBACK(sp_selection_layout_widget_change_selection), desktop); + INKSCAPE.signal_selection_modified.connect(sigc::mem_fun(*holder, &SelectToolbar::on_inkscape_selection_modified)); + INKSCAPE.signal_selection_changed.connect(sigc::mem_fun(*holder, &SelectToolbar::on_inkscape_selection_changed)); // Update now. - sp_selection_layout_widget_update(SP_WIDGET(spw), SP_ACTIVE_DESKTOP ? SP_ACTIVE_DESKTOP->getSelection() : nullptr); + holder->layout_widget_update(SP_ACTIVE_DESKTOP ? SP_ACTIVE_DESKTOP->getSelection() : nullptr); - for (auto & contextAction : *contextActions) { + for (auto & contextAction : *holder->_context_actions) { if ( gtk_action_is_sensitive(contextAction) ) { gtk_action_set_sensitive( contextAction, FALSE ); } } - // Insert spw into the toolbar. - if ( GTK_IS_BOX(holder) ) { - gtk_box_pack_start(GTK_BOX(holder), spw, FALSE, FALSE, 0); - } else if ( GTK_IS_TOOLBAR(holder) ) { - GtkToolItem *spw_toolitem = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(spw_toolitem), spw); - gtk_toolbar_insert(GTK_TOOLBAR(holder), spw_toolitem, -1); - } else { - g_warning("Unexpected holder type"); - } + // Insert vb into the toolbar. + GtkToolItem *vb_toolitem = gtk_tool_item_new(); + gtk_container_add(GTK_CONTAINER(vb_toolitem), vb); + holder->insert(*Glib::wrap(vb_toolitem), -1); + // "Transform with object" buttons { @@ -596,8 +381,218 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_pattern), desktop) ; gtk_action_group_add_action( mainActions, GTK_ACTION(itact) ); } + + return GTK_WIDGET(holder->gobj()); } +void +SelectToolbar::any_value_changed(Glib::RefPtr<Gtk::Adjustment>& adj) +{ + if (_update) { + return; + } + + if ( !_tracker || _tracker->isUpdating() ) { + /* + * When only units are being changed, don't treat changes + * to adjuster values as object changes. + */ + return; + } + _update = true; + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::Selection *selection = desktop->getSelection(); + SPDocument *document = desktop->getDocument(); + + document->ensureUpToDate (); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + Geom::OptRect bbox_vis = selection->visualBounds(); + Geom::OptRect bbox_geom = selection->geometricBounds(); + + int prefs_bbox = prefs->getInt("/tools/bounding_box"); + SPItem::BBoxType bbox_type = (prefs_bbox == 0)? + SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + Geom::OptRect bbox_user = selection->bounds(bbox_type); + + if ( !bbox_user ) { + _update = false; + return; + } + + gdouble x0 = 0; + gdouble y0 = 0; + gdouble x1 = 0; + gdouble y1 = 0; + gdouble xrel = 0; + gdouble yrel = 0; + Unit const *unit = _tracker->getActiveUnit(); + g_return_if_fail(unit != nullptr); + + if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { + x0 = Quantity::convert(_adj_x->get_value(), unit, "px"); + y0 = Quantity::convert(_adj_y->get_value(), unit, "px"); + x1 = x0 + Quantity::convert(_adj_w->get_value(), unit, "px"); + xrel = Quantity::convert(_adj_w->get_value(), unit, "px") / bbox_user->dimensions()[Geom::X]; + y1 = y0 + Quantity::convert(_adj_h->get_value(), unit, "px");; + yrel = Quantity::convert(_adj_h->get_value(), unit, "px") / bbox_user->dimensions()[Geom::Y]; + } else { + double const x0_propn = _adj_x->get_value() / 100 / unit->factor; + x0 = bbox_user->min()[Geom::X] * x0_propn; + double const y0_propn = _adj_y->get_value() / 100 / unit->factor; + y0 = y0_propn * bbox_user->min()[Geom::Y]; + xrel = _adj_w->get_value() / (100 / unit->factor); + x1 = x0 + xrel * bbox_user->dimensions()[Geom::X]; + yrel = _adj_h->get_value() / (100 / unit->factor); + y1 = y0 + yrel * bbox_user->dimensions()[Geom::Y]; + } + + // Keep proportions if lock is on + if ( gtk_toggle_action_get_active(_lock) ) { + if (adj == _adj_h) { + x1 = x0 + yrel * bbox_user->dimensions()[Geom::X]; + } else if (adj == _adj_w) { + y1 = y0 + xrel * bbox_user->dimensions()[Geom::Y]; + } + } + + // scales and moves, in px + double mh = fabs(x0 - bbox_user->min()[Geom::X]); + double sh = fabs(x1 - bbox_user->max()[Geom::X]); + double mv = fabs(y0 - bbox_user->min()[Geom::Y]); + double sv = fabs(y1 - bbox_user->max()[Geom::Y]); + + // unless the unit is %, convert the scales and moves to the unit + if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { + mh = Quantity::convert(mh, "px", unit); + sh = Quantity::convert(sh, "px", unit); + mv = Quantity::convert(mv, "px", unit); + sv = Quantity::convert(sv, "px", unit); + } + + // do the action only if one of the scales/moves is greater than half the last significant + // digit in the spinbox (currently spinboxes have 3 fractional digits, so that makes 0.0005). If + // the value was changed by the user, the difference will be at least that much; otherwise it's + // just rounding difference between the spinbox value and actual value, so no action is + // performed + char const * const actionkey = ( mh > 5e-4 ? "selector:toolbar:move:horizontal" : + sh > 5e-4 ? "selector:toolbar:scale:horizontal" : + mv > 5e-4 ? "selector:toolbar:move:vertical" : + sv > 5e-4 ? "selector:toolbar:scale:vertical" : nullptr ); + + if (actionkey != nullptr) { + + // FIXME: fix for GTK breakage, see comment in SelectedStyle::on_opacity_changed + desktop->getCanvas()->forceFullRedrawAfterInterruptions(0); + + bool transform_stroke = prefs->getBool("/options/transform/stroke", true); + bool preserve = prefs->getBool("/options/preservetransform/value", false); + + Geom::Affine scaler; + if (bbox_type == SPItem::VISUAL_BBOX) { + scaler = get_scale_transform_for_variable_stroke (*bbox_vis, *bbox_geom, transform_stroke, preserve, x0, y0, x1, y1); + } else { + // 1) We could have use the newer get_scale_transform_for_variable_stroke() here, but to avoid regressions + // we'll just use the old get_scale_transform_for_uniform_stroke() for now. + // 2) get_scale_transform_for_uniform_stroke() is intended for visual bounding boxes, not geometrical ones! + // we'll trick it into using a geometric bounding box though, by setting the stroke width to zero + scaler = get_scale_transform_for_uniform_stroke (*bbox_geom, 0, 0, false, false, x0, y0, x1, y1); + } + + selection->applyAffine(scaler); + DocumentUndo::maybeDone(document, actionkey, SP_VERB_CONTEXT_SELECT, + _("Transform by toolbar")); + + // resume interruptibility + desktop->getCanvas()->endForcedFullRedraws(); + } + + _update = false; +} + +void +SelectToolbar::layout_widget_update(Inkscape::Selection *sel) +{ + if (_update) { + return; + } + + _update = true; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + using Geom::X; + using Geom::Y; + if ( sel && !sel->isEmpty() ) { + int prefs_bbox = prefs->getInt("/tools/bounding_box", 0); + SPItem::BBoxType bbox_type = (prefs_bbox ==0)? + SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + Geom::OptRect const bbox(sel->bounds(bbox_type)); + if ( bbox ) { + Unit const *unit = _tracker->getActiveUnit(); + g_return_if_fail(unit != nullptr); + + struct { char const *key; double val; } const keyval[] = { + { "X", bbox->min()[X] }, + { "Y", bbox->min()[Y] }, + { "width", bbox->dimensions()[X] }, + { "height", bbox->dimensions()[Y] } + }; + + if (unit->type == Inkscape::Util::UNIT_TYPE_DIMENSIONLESS) { + double const val = unit->factor * 100; + _adj_x->set_value(val); + _adj_y->set_value(val); + _adj_w->set_value(val); + _adj_h->set_value(val); + _tracker->setFullVal( _adj_x->gobj(), keyval[0].val ); + _tracker->setFullVal( _adj_y->gobj(), keyval[1].val ); + _tracker->setFullVal( _adj_w->gobj(), keyval[2].val ); + _tracker->setFullVal( _adj_h->gobj(), keyval[3].val ); + } else { + _adj_x->set_value(Quantity::convert(keyval[0].val, "px", unit)); + _adj_y->set_value(Quantity::convert(keyval[1].val, "px", unit)); + _adj_w->set_value(Quantity::convert(keyval[2].val, "px", unit)); + _adj_h->set_value(Quantity::convert(keyval[3].val, "px", unit)); + } + } + } + + _update = false; +} + +void +SelectToolbar::on_inkscape_selection_modified(Inkscape::Selection *selection, guint flags) +{ + if ((_desktop->getSelection() == selection) // only respond to changes in our desktop + && (flags & (SP_OBJECT_MODIFIED_FLAG | + SP_OBJECT_PARENT_MODIFIED_FLAG | + SP_OBJECT_CHILD_MODIFIED_FLAG ))) + { + layout_widget_update(selection); + } +} + +void +SelectToolbar::on_inkscape_selection_changed(Inkscape::Selection *selection) +{ + if (_desktop->getSelection() == selection) { // only respond to changes in our desktop + gboolean setActive = (selection && !selection->isEmpty()); + if ( _context_actions ) { + for (auto & contextAction : *_context_actions) { + if ( setActive != gtk_action_is_sensitive(contextAction) ) { + gtk_action_set_sensitive( contextAction, setActive ); + } + } + } + + layout_widget_update(selection); + } +} + +} +} +} /* Local Variables: |
