summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Valavanis <valavanisalex@gmail.com>2019-01-22 22:44:11 +0000
committerAlexander Valavanis <valavanisalex@gmail.com>2019-01-22 22:44:11 +0000
commit72da9a0a50fe3e075e85636fce0942bf0a90d799 (patch)
treee4bf16375312cedf63acd311ad1aeb000febde9e
parentMerge branch 'master' of gitlab.com:inkscape/inkscape (diff)
downloadinkscape-72da9a0a50fe3e075e85636fce0942bf0a90d799.tar.gz
inkscape-72da9a0a50fe3e075e85636fce0942bf0a90d799.zip
SelectToolbar: GtkAction migration
-rw-r--r--share/ui/select-toolbar.ui3
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/toolbar/select-toolbar.cpp521
-rw-r--r--src/ui/toolbar/select-toolbar.h15
-rw-r--r--src/ui/widget/spin-button-tool-item.cpp421
-rw-r--r--src/ui/widget/spin-button-tool-item.h76
-rw-r--r--src/widgets/toolbox.cpp2
7 files changed, 740 insertions, 300 deletions
diff --git a/share/ui/select-toolbar.ui b/share/ui/select-toolbar.ui
index 04d9e2b4f..f62cd705e 100644
--- a/share/ui/select-toolbar.ui
+++ b/share/ui/select-toolbar.ui
@@ -1,4 +1,5 @@
<ui>
+<!--
<toolbar name='SelectToolbar'>
<toolitem action='EditSelectAll' />
<toolitem action='EditSelectAllInAllLayers' />
@@ -26,7 +27,7 @@
<toolitem action='transform_gradient' />
<toolitem action='transform_pattern' />
</toolbar>
-
+-->
<toolbar name='NodeToolbar'>
<separator />
<toolitem action='NodeInsertAction'>
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 8cc446609..7125a4aa2 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -197,6 +197,7 @@ set(ui_SRC
widget/scalar-unit.cpp
widget/scalar.cpp
widget/selected-style.cpp
+ widget/spin-button-tool-item.cpp
widget/spin-scale.cpp
widget/spin-slider.cpp
widget/spinbutton.cpp
@@ -427,6 +428,7 @@ set(ui_SRC
widget/scalar-unit.h
widget/scalar.h
widget/selected-style.h
+ widget/spin-button-tool-item.h
widget/spin-scale.h
widget/spin-slider.h
widget/spinbutton.h
diff --git a/src/ui/toolbar/select-toolbar.cpp b/src/ui/toolbar/select-toolbar.cpp
index 7c463601f..764280b18 100644
--- a/src/ui/toolbar/select-toolbar.cpp
+++ b/src/ui/toolbar/select-toolbar.cpp
@@ -15,6 +15,8 @@
#include <glibmm/i18n.h>
+#include <gtkmm/separatortoolitem.h>
+
#include <2geom/rect.h>
#include "select-toolbar.h"
@@ -22,9 +24,6 @@
#include "desktop.h"
#include "document-undo.h"
#include "document.h"
-#include "widgets/ink-action.h"
-#include "widgets/ink-toggle-action.h"
-#include "widgets/toolbox.h"
#include "inkscape.h"
#include "message-stack.h"
#include "selection-chemistry.h"
@@ -41,6 +40,7 @@
#include "ui/icon-names.h"
#include "ui/widget/ink-select-one-action.h"
#include "ui/widget/spinbutton.h"
+#include "ui/widget/spin-button-tool-item.h"
#include "ui/widget/unit-tracker.h"
#include "widgets/ege-adjustment-action.h"
@@ -54,69 +54,6 @@ using Inkscape::Util::unit_table;
-// toggle button callbacks and updaters
-
-static void toggle_stroke( GtkToggleAction* act, gpointer data )
-{
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- gboolean active = gtk_toggle_action_get_active(act);
- prefs->setBool("/options/transform/stroke", active);
- SPDesktop *desktop = static_cast<SPDesktop *>(data);
- if ( active ) {
- desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>stroke width</b> is <b>scaled</b> when objects are scaled."));
- } else {
- desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>stroke width</b> is <b>not scaled</b> when objects are scaled."));
- }
-}
-
-static void toggle_corners( GtkToggleAction* act, gpointer data)
-{
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- gboolean active = gtk_toggle_action_get_active(act);
- prefs->setBool("/options/transform/rectcorners", active);
- SPDesktop *desktop = static_cast<SPDesktop *>(data);
- if ( active ) {
- desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>rounded rectangle corners</b> are <b>scaled</b> when rectangles are scaled."));
- } else {
- desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>rounded rectangle corners</b> are <b>not scaled</b> when rectangles are scaled."));
- }
-}
-
-static void toggle_gradient( GtkToggleAction *act, gpointer data )
-{
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- gboolean active = gtk_toggle_action_get_active(act);
- prefs->setBool("/options/transform/gradient", active);
- SPDesktop *desktop = static_cast<SPDesktop *>(data);
- if ( active ) {
- 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)."));
- } else {
- desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>gradients</b> remain <b>fixed</b> when objects are transformed (moved, scaled, rotated, or skewed)."));
- }
-}
-
-static void toggle_pattern( GtkToggleAction* act, gpointer data )
-{
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- gboolean active = gtk_toggle_action_get_active(act);
- prefs->setInt("/options/transform/pattern", active);
- SPDesktop *desktop = static_cast<SPDesktop *>(data);
- if ( active ) {
- 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)."));
- } else {
- desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>patterns</b> remain <b>fixed</b> when objects are transformed (moved, scaled, rotated, or skewed)."));
- }
-}
-
-static void toggle_lock( GtkToggleAction *act, gpointer /*data*/ ) {
- gboolean active = gtk_toggle_action_get_active( act );
- if ( active ) {
- g_object_set( G_OBJECT(act), "iconId", INKSCAPE_ICON("object-locked"), NULL );
- } else {
- g_object_set( G_OBJECT(act), "iconId", INKSCAPE_ICON("object-unlocked"), NULL );
- }
-}
-
static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
{
SPAction* targetAction = SP_ACTION(user_data);
@@ -125,249 +62,183 @@ static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data )
}
}
-static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, GtkIconSize size )
-{
- GtkAction* act = nullptr;
-
- SPAction* targetAction = verb->get_action(Inkscape::ActionContext(view));
- InkAction* inky = ink_action_new( verb->get_id(), verb->get_name(), verb->get_tip(), verb->get_image(), size );
- act = GTK_ACTION(inky);
-
- g_signal_connect( G_OBJECT(inky), "activate", G_CALLBACK(trigger_sp_action), targetAction );
-
- return act;
-}
-
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)
-{}
-
-GtkWidget *
-SelectToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions)
+ _update(false),
+ _lock_btn(Gtk::manage(new Gtk::ToggleToolButton())),
+ _transform_stroke_btn(Gtk::manage(new Gtk::ToggleToolButton())),
+ _transform_corners_btn(Gtk::manage(new Gtk::ToggleToolButton())),
+ _transform_gradient_btn(Gtk::manage(new Gtk::ToggleToolButton())),
+ _transform_pattern_btn(Gtk::manage(new Gtk::ToggleToolButton()))
{
- 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;
-
- 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( 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( holder->_selection_actions, act );
- act = create_action_for_verb( Inkscape::Verb::get(SP_VERB_EDIT_DESELECT), view, secondarySize );
- 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( 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( 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( 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( 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( 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( 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( 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( holder->_selection_actions, act );
- holder->_context_actions->push_back( act );
-
- // Create the parent widget for x y w h tracker.
- // 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);
-
- // Create the units menu.
- holder->_tracker->addUnit(unit_table.getUnit("%"));
- holder->_tracker->setActiveUnit( desktop->getNamedView()->display_units );
-
- EgeAdjustmentAction* eact = nullptr;
-
- // four spinbuttons
-
- eact = create_adjustment_action(
- "XAction", /* name */
- C_("Select toolbar", "X position"), /* label */
- C_("Select toolbar", "X:"), /* shortLabel */
- C_("Select toolbar", "Horizontal coordinate of selection"), /* tooltip */
- "/tools/select/X", /* path */
- 0.0, /* def(default) */
- TRUE, "altx", /* altx, altx_mark */
- -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */
- nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */
- holder->_tracker.get(), /* unit_tracker */
- SPIN_STEP, 3, 1); /* climb, digits, factor */
- ege_adjustment_action_set_focuswidget(eact, GTK_WIDGET(desktop->canvas));
-
- 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 */
- C_("Select toolbar", "Y position"), /* label */
- C_("Select toolbar", "Y:"), /* shortLabel */
- C_("Select toolbar", "Vertical coordinate of selection"), /* tooltip */
- "/tools/select/Y", /* path */
- 0.0, /* def(default) */
- TRUE, "altx", /* altx, altx_mark */
- -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */
- nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */
- holder->_tracker.get(), /* unit_tracker */
- SPIN_STEP, 3, 1); /* climb, digits, factor */
- ege_adjustment_action_set_focuswidget(eact, GTK_WIDGET(desktop->canvas));
-
- 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 */
- C_("Select toolbar", "Width"), /* label */
- C_("Select toolbar", "W:"), /* shortLabel */
- C_("Select toolbar", "Width of selection"), /* tooltip */
- "/tools/select/width", /* path */
- 0.0, /* def(default) */
- TRUE, "altx", /* altx, altx_mark */
- 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */
- nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */
- holder->_tracker.get(), /* unit_tracker */
- SPIN_STEP, 3, 1); /* climb, digits, factor */
- ege_adjustment_action_set_focuswidget(eact, GTK_WIDGET(desktop->canvas));
-
- 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) );
+ auto select_all_button = add_toolbutton_for_verb(SP_VERB_EDIT_SELECT_ALL);
+ auto select_all_in_all_layers_button = add_toolbutton_for_verb(SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS);
+ auto deselect_button = add_toolbutton_for_verb(SP_VERB_EDIT_DESELECT);
+ _context_items.push_back(deselect_button);
+
+ add(* Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ auto object_rotate_90_ccw_button = add_toolbutton_for_verb(SP_VERB_OBJECT_ROTATE_90_CCW);
+ _context_items.push_back(object_rotate_90_ccw_button);
+
+ auto object_rotate_90_cw_button = add_toolbutton_for_verb(SP_VERB_OBJECT_ROTATE_90_CW);
+ _context_items.push_back(object_rotate_90_cw_button);
+
+ auto object_flip_horizontal_button = add_toolbutton_for_verb(SP_VERB_OBJECT_FLIP_HORIZONTAL);
+ _context_items.push_back(object_flip_horizontal_button);
+
+ auto object_flip_vertical_button = add_toolbutton_for_verb(SP_VERB_OBJECT_FLIP_VERTICAL);
+ _context_items.push_back(object_flip_vertical_button);
+
+ add(* Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ auto selection_to_back_button = add_toolbutton_for_verb(SP_VERB_SELECTION_TO_BACK);
+ _context_items.push_back(selection_to_back_button);
+
+ auto selection_lower_button = add_toolbutton_for_verb(SP_VERB_SELECTION_LOWER);
+ _context_items.push_back(selection_lower_button);
+
+ auto selection_raise_button = add_toolbutton_for_verb(SP_VERB_SELECTION_RAISE);
+ _context_items.push_back(selection_raise_button);
+
+ auto selection_to_front_button = add_toolbutton_for_verb(SP_VERB_SELECTION_TO_FRONT);
+ _context_items.push_back(selection_to_front_button);
+
+ add(* Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ _tracker->addUnit(unit_table.getUnit("%"));
+ _tracker->setActiveUnit( desktop->getNamedView()->display_units );
+
+ // x-value control
+ auto x_val = prefs->getDouble("/tools/select/X", 0.0);
+ _adj_x = Gtk::Adjustment::create(x_val, -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP);
+ _adj_x->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*this, &SelectToolbar::any_value_changed), _adj_x));
+ _tracker->addAdjustment(_adj_x->gobj());
+
+ auto x_btn = Gtk::manage(new UI::Widget::SpinButtonToolItem("select-x",
+ C_("Select toolbar", "X:"),
+ _adj_x,
+ SPIN_STEP, 3));
+ x_btn->set_focus_widget(Glib::wrap(GTK_WIDGET(_desktop->canvas)));
+ x_btn->set_all_tooltip_text(C_("Select toolbar", "Horizontal coordinate of selection"));
+ _context_items.push_back(x_btn);
+ add(*x_btn);
+
+ // y-value control
+ auto y_val = prefs->getDouble("/tools/select/Y", 0.0);
+ _adj_y = Gtk::Adjustment::create(y_val, -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP);
+ _adj_y->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*this, &SelectToolbar::any_value_changed), _adj_y));
+ _tracker->addAdjustment(_adj_y->gobj());
+
+ auto y_btn = Gtk::manage(new UI::Widget::SpinButtonToolItem("select-y",
+ C_("Select toolbar", "Y:"),
+ _adj_y,
+ SPIN_STEP, 3));
+ y_btn->set_focus_widget(Glib::wrap(GTK_WIDGET(_desktop->canvas)));
+ y_btn->set_all_tooltip_text(C_("Select toolbar", "Vertical coordinate of selection"));
+ _context_items.push_back(y_btn);
+ add(*y_btn);
+
+ // width-value control
+ auto w_val = prefs->getDouble("/tools/select/width", 0.0);
+ _adj_w = Gtk::Adjustment::create(w_val, 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP);
+ _adj_w->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*this, &SelectToolbar::any_value_changed), _adj_w));
+ _tracker->addAdjustment(_adj_w->gobj());
+
+ auto w_btn = Gtk::manage(new UI::Widget::SpinButtonToolItem("select-width",
+ C_("Select toolbar", "W:"),
+ _adj_w,
+ SPIN_STEP, 3));
+ w_btn->set_focus_widget(Glib::wrap(GTK_WIDGET(_desktop->canvas)));
+ w_btn->set_all_tooltip_text(C_("Select toolbar", "Width of selection"));
+ _context_items.push_back(w_btn);
+ add(*w_btn);
// lock toggle
- {
- 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(
- "HeightAction", /* name */
- C_("Select toolbar", "Height"), /* label */
- C_("Select toolbar", "H:"), /* shortLabel */
- C_("Select toolbar", "Height of selection"), /* tooltip */
- "/tools/select/height", /* path */
- 0.0, /* def(default) */
- TRUE, "altx", /* altx, altx_mark */
- 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, upper, step, page */
- nullptr, nullptr, 0, /* descrLabels, descrValues, descrCount */
- holder->_tracker.get(), /* unit_tracker */
- SPIN_STEP, 3, 1); /* climb, digits, factor */
- ege_adjustment_action_set_focuswidget(eact, GTK_WIDGET(desktop->canvas));
- 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 = holder->_tracker->createAction( "UnitsAction", _("Units"), ("") );
- gtk_action_group_add_action( holder->_selection_actions, act->gobj() );
- }
+ _lock_btn->set_label(_("Lock width and height"));
+ _lock_btn->set_tooltip_text(_("When locked, change both width and height by the same proportion"));
+ _lock_btn->set_icon_name(INKSCAPE_ICON("object-unlocked"));
+ _lock_btn->signal_toggled().connect(sigc::mem_fun(*this, &SelectToolbar::toggle_lock));
+ add(*_lock_btn);
+
+ // height-value control
+ auto h_val = prefs->getDouble("/tools/select/height", 0.0);
+ _adj_h = Gtk::Adjustment::create(h_val, 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP);
+ _adj_h->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*this, &SelectToolbar::any_value_changed), _adj_h));
+ _tracker->addAdjustment(_adj_h->gobj());
+
+ auto h_btn = Gtk::manage(new UI::Widget::SpinButtonToolItem("select-height",
+ C_("Select toolbar", "H:"),
+ _adj_h,
+ SPIN_STEP, 3));
+ h_btn->set_focus_widget(Glib::wrap(GTK_WIDGET(_desktop->canvas)));
+ h_btn->set_all_tooltip_text(C_("Select toolbar", "Height of selection"));
+ _context_items.push_back(h_btn);
+ add(*h_btn);
+
+ // units menu
+ auto unit_menu = _tracker->createAction( "UnitsAction", _("Units"), ("") );
+ auto unit_menu_ti = unit_menu->create_tool_item();
+ add(*unit_menu_ti);
+
+ add(* Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ _transform_stroke_btn->set_label(_("Scale stroke width"));
+ _transform_stroke_btn->set_tooltip_text(_("When scaling objects, scale the stroke width by the same proportion"));
+ _transform_stroke_btn->set_icon_name(INKSCAPE_ICON("transform-affect-stroke"));
+ _transform_stroke_btn->set_active(prefs->getBool("/options/transform/stroke", true));
+ _transform_stroke_btn->signal_toggled().connect(sigc::mem_fun(*this, &SelectToolbar::toggle_stroke));
+ add(*_transform_stroke_btn);
+
+ _transform_corners_btn->set_label(_("Scale rounded corners"));
+ _transform_corners_btn->set_tooltip_text(_("When scaling rectangles, scale the radii of rounded corners"));
+ _transform_corners_btn->set_icon_name(INKSCAPE_ICON("transform-affect-rounded-corners"));
+ _transform_corners_btn->set_active(prefs->getBool("/options/transform/rectcorners", true));
+ _transform_corners_btn->signal_toggled().connect(sigc::mem_fun(*this, &SelectToolbar::toggle_corners));
+ add(*_transform_corners_btn);
+
+ _transform_gradient_btn->set_label(_("Move gradients"));
+ _transform_gradient_btn->set_tooltip_text(_("Move gradients (in fill or stroke) along with the objects"));
+ _transform_gradient_btn->set_icon_name(INKSCAPE_ICON("transform-affect-gradient"));
+ _transform_gradient_btn->set_active(prefs->getBool("/options/transform/gradient", true));
+ _transform_gradient_btn->signal_toggled().connect(sigc::mem_fun(*this, &SelectToolbar::toggle_gradient));
+ add(*_transform_gradient_btn);
+
+ _transform_pattern_btn->set_label(_("Move patterns"));
+ _transform_pattern_btn->set_tooltip_text(_("Move patterns (in fill or stroke) along with the objects"));
+ _transform_pattern_btn->set_icon_name(INKSCAPE_ICON("transform-affect-pattern"));
+ _transform_pattern_btn->set_active(prefs->getBool("/options/transform/pattern", true));
+ _transform_pattern_btn->signal_toggled().connect(sigc::mem_fun(*this, &SelectToolbar::toggle_pattern));
+ add(*_transform_pattern_btn);
// Force update when selection changes.
- 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));
+ INKSCAPE.signal_selection_modified.connect(sigc::mem_fun(*this, &SelectToolbar::on_inkscape_selection_modified));
+ INKSCAPE.signal_selection_changed.connect (sigc::mem_fun(*this, &SelectToolbar::on_inkscape_selection_changed));
// Update now.
- holder->layout_widget_update(SP_ACTIVE_DESKTOP ? SP_ACTIVE_DESKTOP->getSelection() : nullptr);
+ layout_widget_update(SP_ACTIVE_DESKTOP ? SP_ACTIVE_DESKTOP->getSelection() : nullptr);
- for (auto & contextAction : *holder->_context_actions) {
- if ( gtk_action_is_sensitive(contextAction) ) {
- gtk_action_set_sensitive( contextAction, FALSE );
+ for (auto item : _context_items) {
+ if ( item->is_sensitive() ) {
+ item->set_sensitive(false);
}
}
- // 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
- {
-
- InkToggleAction* itact = ink_toggle_action_new( "transform_stroke",
- _("Scale stroke width"),
- _("When scaling objects, scale the stroke width by the same proportion"),
- "transform-affect-stroke",
- secondarySize );
- gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/stroke", true) );
- g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_stroke), desktop) ;
- gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
- }
-
- {
- InkToggleAction* itact = ink_toggle_action_new( "transform_corners",
- _("Scale rounded corners"),
- _("When scaling rectangles, scale the radii of rounded corners"),
- "transform-affect-rounded-corners",
- secondarySize );
- gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/rectcorners", true) );
- g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_corners), desktop) ;
- gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
- }
-
- {
- InkToggleAction* itact = ink_toggle_action_new( "transform_gradient",
- _("Move gradients"),
- _("Move gradients (in fill or stroke) along with the objects"),
- "transform-affect-gradient",
- secondarySize );
- gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/gradient", true) );
- g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_gradient), desktop) ;
- gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
- }
-
- {
- InkToggleAction* itact = ink_toggle_action_new( "transform_pattern",
- _("Move patterns"),
- _("Move patterns (in fill or stroke) along with the objects"),
- "transform-affect-pattern",
- secondarySize );
- gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/pattern", true) );
- g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_pattern), desktop) ;
- gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
- }
+ show_all();
+}
- return GTK_WIDGET(holder->gobj());
+GtkWidget *
+SelectToolbar::create(SPDesktop *desktop)
+{
+ auto toolbar = new SelectToolbar(desktop);
+ return GTK_WIDGET(toolbar->gobj());
}
void
@@ -434,7 +305,7 @@ SelectToolbar::any_value_changed(Glib::RefPtr<Gtk::Adjustment>& adj)
}
// Keep proportions if lock is on
- if ( gtk_toggle_action_get_active(_lock) ) {
+ if ( _lock_btn->get_active() ) {
if (adj == _adj_h) {
x1 = x0 + yrel * bbox_user->dimensions()[Geom::X];
} else if (adj == _adj_w) {
@@ -562,12 +433,11 @@ 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 );
- }
+ bool setActive = (selection && !selection->isEmpty());
+
+ for (auto item : _context_items) {
+ if ( setActive != item->get_sensitive() ) {
+ item->set_sensitive(setActive);
}
}
@@ -575,6 +445,67 @@ SelectToolbar::on_inkscape_selection_changed(Inkscape::Selection *selection)
}
}
+void
+SelectToolbar::toggle_lock() {
+ if ( _lock_btn->get_active() ) {
+ _lock_btn->set_icon_name(INKSCAPE_ICON("object-locked"));
+ } else {
+ _lock_btn->set_icon_name(INKSCAPE_ICON("object-unlocked"));
+ }
+}
+
+void
+SelectToolbar::toggle_stroke()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool active = _transform_stroke_btn->get_active();
+ prefs->setBool("/options/transform/stroke", active);
+ if ( active ) {
+ _desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>stroke width</b> is <b>scaled</b> when objects are scaled."));
+ } else {
+ _desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>stroke width</b> is <b>not scaled</b> when objects are scaled."));
+ }
+}
+
+void
+SelectToolbar::toggle_corners()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool active = _transform_corners_btn->get_active();
+ prefs->setBool("/options/transform/rectcorners", active);
+ if ( active ) {
+ _desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>rounded rectangle corners</b> are <b>scaled</b> when rectangles are scaled."));
+ } else {
+ _desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>rounded rectangle corners</b> are <b>not scaled</b> when rectangles are scaled."));
+ }
+}
+
+void
+SelectToolbar::toggle_gradient()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool active = _transform_gradient_btn->get_active();
+ prefs->setBool("/options/transform/gradient", active);
+ if ( active ) {
+ _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)."));
+ } else {
+ _desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>gradients</b> remain <b>fixed</b> when objects are transformed (moved, scaled, rotated, or skewed)."));
+ }
+}
+
+void
+SelectToolbar::toggle_pattern()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool active = _transform_pattern_btn->get_active();
+ prefs->setInt("/options/transform/pattern", active);
+ if ( active ) {
+ _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)."));
+ } else {
+ _desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Now <b>patterns</b> remain <b>fixed</b> when objects are transformed (moved, scaled, rotated, or skewed)."));
+ }
+}
+
}
}
}
diff --git a/src/ui/toolbar/select-toolbar.h b/src/ui/toolbar/select-toolbar.h
index 30caa3779..f233b62c8 100644
--- a/src/ui/toolbar/select-toolbar.h
+++ b/src/ui/toolbar/select-toolbar.h
@@ -40,10 +40,14 @@ private:
Glib::RefPtr<Gtk::Adjustment> _adj_y;
Glib::RefPtr<Gtk::Adjustment> _adj_w;
Glib::RefPtr<Gtk::Adjustment> _adj_h;
- GtkToggleAction *_lock;
+ Gtk::ToggleToolButton *_lock_btn;
+ Gtk::ToggleToolButton *_transform_stroke_btn;
+ Gtk::ToggleToolButton *_transform_corners_btn;
+ Gtk::ToggleToolButton *_transform_gradient_btn;
+ Gtk::ToggleToolButton *_transform_pattern_btn;
GtkActionGroup *_selection_actions;
- std::vector<GtkAction *> *_context_actions;
+ std::vector<Gtk::ToolItem *> _context_items;
bool _update;
@@ -51,12 +55,17 @@ private:
void layout_widget_update(Inkscape::Selection *sel);
void on_inkscape_selection_modified(Inkscape::Selection *selection, guint flags);
void on_inkscape_selection_changed(Inkscape::Selection *selection);
+ void toggle_lock();
+ void toggle_stroke();
+ void toggle_corners();
+ void toggle_gradient();
+ void toggle_pattern();
protected:
SelectToolbar(SPDesktop *desktop);
public:
- static GtkWidget * prep(SPDesktop *desktop, GtkActionGroup* mainActions);
+ static GtkWidget * create(SPDesktop *desktop);
};
}
diff --git a/src/ui/widget/spin-button-tool-item.cpp b/src/ui/widget/spin-button-tool-item.cpp
new file mode 100644
index 000000000..3e510923c
--- /dev/null
+++ b/src/ui/widget/spin-button-tool-item.cpp
@@ -0,0 +1,421 @@
+#include "spin-button-tool-item.h"
+
+#include <gtkmm/box.h>
+#include <gtkmm/radiomenuitem.h>
+#include <gtkmm/toolbar.h>
+
+#include "spinbutton.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+/**
+ * \brief Handler for the button's "focus-in-event" signal
+ *
+ * \param focus_event The event that triggered the signal
+ *
+ * \detail This just logs the current value of the spin-button
+ * and sets the _transfer_focus flag
+ */
+bool
+SpinButtonToolItem::on_btn_focus_in_event(GdkEventFocus * /* focus_event */)
+{
+ _last_val = _btn->get_value();
+ _transfer_focus = true;
+
+ return false; // Event not consumed
+}
+
+/**
+ * \brief Handler for the button's "focus-out-event" signal
+ *
+ * \param focus_event The event that triggered the signal
+ *
+ * \detail This just unsets the _transfer_focus flag
+ */
+bool
+SpinButtonToolItem::on_btn_focus_out_event(GdkEventFocus * /* focus_event */)
+{
+ _transfer_focus = false;
+
+ return false; // Event not consumed
+}
+
+/**
+ * \brief Handler for the button's "key-press-event" signal
+ *
+ * \param key_event The event that triggered the signal
+ *
+ * \detail If the ESC key was pressed, restore the last value and defocus.
+ * If the Enter key was pressed, just defocus.
+ */
+bool
+SpinButtonToolItem::on_btn_key_press_event(GdkEventKey *key_event)
+{
+ bool was_consumed = false; // Whether event has been consumed or not
+ auto display = Gdk::Display::get_default();
+ auto keymap = display->get_keymap();
+ guint key = 0;
+ gdk_keymap_translate_keyboard_state(keymap, key_event->hardware_keycode,
+ static_cast<GdkModifierType>(key_event->state),
+ 0, &key, 0, 0, 0);
+
+ auto val = _btn->get_value();
+
+ switch(key) {
+ case GDK_KEY_Escape:
+ {
+ _transfer_focus = true;
+ _btn->set_value(_last_val);
+ defocus();
+ was_consumed = true;
+ }
+ break;
+
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter:
+ {
+ _transfer_focus = true;
+ defocus();
+ was_consumed = true;
+ }
+ break;
+
+ case GDK_KEY_Tab:
+ {
+ _transfer_focus = false;
+ was_consumed = process_tab(1);
+ }
+ break;
+
+ case GDK_KEY_ISO_Left_Tab:
+ {
+ _transfer_focus = false;
+ was_consumed = process_tab(-1);
+ }
+ break;
+
+ // TODO: Enable variable step-size if this is ever used
+ case GDK_KEY_Up:
+ case GDK_KEY_KP_Up:
+ {
+ _transfer_focus = false;
+ _btn->set_value(val+1);
+ was_consumed=true;
+ }
+ break;
+
+ case GDK_KEY_Down:
+ case GDK_KEY_KP_Down:
+ {
+ _transfer_focus = false;
+ _btn->set_value(val-1);
+ was_consumed=true;
+ }
+ break;
+
+ case GDK_KEY_Page_Up:
+ case GDK_KEY_KP_Page_Up:
+ {
+ _transfer_focus = false;
+ _btn->set_value(val+10);
+ was_consumed=true;
+ }
+ break;
+
+ case GDK_KEY_Page_Down:
+ case GDK_KEY_KP_Page_Down:
+ {
+ _transfer_focus = false;
+ _btn->set_value(val-10);
+ was_consumed=true;
+ }
+ break;
+
+ case GDK_KEY_z:
+ case GDK_KEY_Z:
+ {
+ _transfer_focus = false;
+ _btn->set_value(_last_val);
+ was_consumed = true;
+ }
+ break;
+ }
+
+ return was_consumed;
+}
+
+/**
+ * \brief Shift focus to a different widget
+ *
+ * \details This only has an effect if the _transfer_focus flag and the _focus_widget are set
+ */
+void
+SpinButtonToolItem::defocus()
+{
+ if(_transfer_focus && _focus_widget) {
+ _focus_widget->grab_focus();
+ }
+}
+
+/**
+ * \brief Move focus to another spinbutton in the toolbar
+ *
+ * \param increment[in] The number of places to shift within the toolbar
+ */
+bool
+SpinButtonToolItem::process_tab(int increment)
+{
+ // If the increment is zero, do nothing
+ if(increment == 0) return true;
+
+ // Here, we're working through the widget heirarchy:
+ // Toolbar
+ // |- ToolItem (*this)
+ // |-> Box
+ // |-> SpinButton (*_btn)
+ //
+ // Our aim is to find the next/previous spin-button within a toolitem in our toolbar
+
+ bool handled = false;
+
+ // We only bother doing this if the current item is actually in a toolbar!
+ auto toolbar = dynamic_cast<Gtk::Toolbar *>(get_parent());
+
+ if (toolbar) {
+ // Get the index of the current item within the toolbar and the total number of items
+ auto my_index = toolbar->get_item_index(*this);
+ auto n_items = toolbar->get_n_items();
+
+ auto test_index = my_index + increment; // The index of the item we want to check
+
+ // Loop through tool items as long as we're within the bounds of the toolbar and
+ // we haven't yet found our new item to focus on
+ while(test_index > 0 && test_index <= n_items && !handled) {
+
+ auto tool_item = toolbar->get_nth_item(test_index);
+
+ if(tool_item) {
+ // There are now two options that we support:
+ if(dynamic_cast<SpinButtonToolItem *>(tool_item)) {
+ // (1) The tool item is a SpinButtonToolItem, in which case, we just pass
+ // focus to its spin-button
+ dynamic_cast<SpinButtonToolItem *>(tool_item)->grab_button_focus();
+ handled = true;
+ }
+ else if(dynamic_cast<Gtk::SpinButton *>(tool_item->get_child())) {
+ // (2) The tool item contains a plain Gtk::SpinButton, in which case we
+ // pass focus directly to it
+ tool_item->get_child()->grab_focus();
+ }
+ }
+
+ test_index += increment;
+ }
+ }
+
+ return handled;
+}
+
+/**
+ * \brief Handler for toggle events on numeric menu items
+ *
+ * \details Sets the adjustment to the desired value
+ */
+void
+SpinButtonToolItem::on_numeric_menu_item_toggled(double value)
+{
+ auto adj = _btn->get_adjustment();
+ adj->set_value(value);
+}
+
+Gtk::RadioMenuItem *
+SpinButtonToolItem::create_numeric_menu_item(Gtk::RadioButtonGroup *group,
+ double value)
+{
+ // Represent the value as a string
+ std::ostringstream ss;
+ ss << value;
+
+ auto numeric_option = Gtk::manage(new Gtk::RadioMenuItem(*group, ss.str()));
+
+ // Set the adjustment value in response to changes in the selected item
+ auto toggled_handler = sigc::bind(sigc::mem_fun(*this, &SpinButtonToolItem::on_numeric_menu_item_toggled), value);
+ numeric_option->signal_toggled().connect(toggled_handler);
+
+ return numeric_option;
+}
+
+/**
+ * \brief Create a menu-item in response to the "create-menu-proxy" signal
+ *
+ * \detail This is an override for the default Gtk::ToolItem handler so
+ * we don't need to explicitly connect this to the signal. It
+ * runs if the toolitem is unable to fit on the toolbar, and
+ * must be represented by a menu item instead.
+ */
+bool
+SpinButtonToolItem::on_create_menu_proxy()
+{
+ // The main menu-item. It just contains the label that normally appears
+ // next to the spin-button, and an indicator for a sub-menu.
+ auto menu_item = Gtk::manage(new Gtk::MenuItem(_label_text));
+
+ // A sub-menu containing fixed numeric options for the
+ // adjustment. Each of these represent "snap-points" for the
+ // adjustment's value.
+ auto sub_menu = Gtk::manage(new Gtk::Menu());
+
+ Gtk::RadioMenuItem::Group group;
+
+ // Get values for the adjustment
+ auto adj = _btn->get_adjustment();
+ auto adj_value = adj->get_value();
+ auto lower = adj->get_lower();
+ auto upper = adj->get_upper();
+ auto range = upper - lower;
+ auto step = range/4.0;
+
+ auto digits = _btn->get_digits();
+
+ // A number a little smaller than the smallest increment that can be
+ // displayed in the spinbutton entry.
+ //
+ // For example, if digits = 0, we are displaying integers only and
+ // epsilon = 0.9 * 10^-0 = 0.9
+ //
+ // For digits = 1, we get epsilon = 0.9 * 10^-1 = 0.09
+ // For digits = 2, we get epsilon = 0.9 * 10^-2 = 0.009 etc...
+ auto epsilon = 0.9 * pow(10.0, -float(digits));
+
+ // For now, let's just set some fixed values at 25% intervals
+ // along the adjustment's range.
+ //
+ // TODO: Allow values for the list to be specified
+ // TODO: Allow descriptions to be added
+ // TODO: Make the range of values depend on current value?
+
+ for (unsigned int i = 0; i < 5; ++i)
+ {
+ // Get the value for this item and represent it as a string
+ auto value = lower + i * step;
+
+ auto numeric_menu_item = create_numeric_menu_item(&group, value);
+ sub_menu->append(*numeric_menu_item);
+
+ if (fabs(adj_value - value) < epsilon) {
+ // If the adjustment value is very close to the value of this menu item,
+ // make this menu item active
+ numeric_menu_item->set_active();
+ }
+ else if (adj_value > value + epsilon &&
+ adj_value < value + step - epsilon)
+ {
+ // Alternatively, if the adjustment value is between this and the
+ // next item, then insert another menu item here
+ auto active_menu_item = create_numeric_menu_item(&group, adj_value);
+ sub_menu->append(*active_menu_item);
+ active_menu_item->set_active();
+ }
+ }
+
+ menu_item->set_submenu(*sub_menu);
+
+ set_proxy_menu_item(_name, *menu_item);
+
+ return true; // Finished handling the event
+}
+
+/**
+ * \brief Create a new SpinButtonToolItem
+ *
+ * \param[in] name A unique ID for this tool-item (not translatable)
+ * \param[in] label_text The text to display in the toolbar
+ * \param[in] adjustment The Gtk::Adjustment to attach to the spinbutton
+ * \param[in] climb_rate The climb rate for the spin button (default = 0)
+ * \param[in] digits Number of decimal places to display
+ */
+SpinButtonToolItem::SpinButtonToolItem(const Glib::ustring& name,
+ const Glib::ustring& label_text,
+ Glib::RefPtr<Gtk::Adjustment>& adjustment,
+ double climb_rate,
+ double digits)
+ : _btn(Gtk::manage(new SpinButton(adjustment, climb_rate, digits))),
+ _name(name),
+ _label_text(label_text),
+ _last_val(0.0),
+ _transfer_focus(false),
+ _focus_widget(nullptr)
+{
+ set_margin_start(3);
+ set_margin_end(3);
+
+ // Handle button events
+ auto btn_focus_in_event_cb = sigc::mem_fun(*this, &SpinButtonToolItem::on_btn_focus_in_event);
+ _btn->signal_focus_in_event().connect(btn_focus_in_event_cb);
+
+ auto btn_focus_out_event_cb = sigc::mem_fun(*this, &SpinButtonToolItem::on_btn_focus_out_event);
+ _btn->signal_focus_out_event().connect(btn_focus_out_event_cb);
+
+ auto btn_key_press_event_cb = sigc::mem_fun(*this, &SpinButtonToolItem::on_btn_key_press_event);
+ _btn->signal_key_press_event().connect(btn_key_press_event_cb);
+
+ _btn->add_events(Gdk::KEY_PRESS_MASK);
+
+ // Create a label
+ auto label = Gtk::manage(new Gtk::Label(label_text));
+
+ // Arrange the widgets in a horizontal box
+ auto hbox = Gtk::manage(new Gtk::Box());
+ hbox->set_spacing(3);
+ hbox->pack_start(*label);
+ hbox->pack_start(*_btn);
+ add(*hbox);
+ show_all();
+}
+
+/**
+ * \brief Set the tooltip to display on this (and all child widgets)
+ *
+ * \param[in] text The tooltip to display
+ */
+void
+SpinButtonToolItem::set_all_tooltip_text(const Glib::ustring& text)
+{
+ set_tooltip_text(text);
+ _btn->set_tooltip_text(text);
+}
+
+/**
+ * \brief Set the widget that focus moves to when this one loses focus
+ *
+ * \param widget The widget that will gain focus
+ */
+void
+SpinButtonToolItem::set_focus_widget(Gtk::Widget *widget)
+{
+ _focus_widget = widget;
+}
+
+/**
+ * \brief Grab focus on the spin-button widget
+ */
+void
+SpinButtonToolItem::grab_button_focus()
+{
+ _btn->grab_focus();
+}
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/ui/widget/spin-button-tool-item.h b/src/ui/widget/spin-button-tool-item.h
new file mode 100644
index 000000000..aff17dd35
--- /dev/null
+++ b/src/ui/widget/spin-button-tool-item.h
@@ -0,0 +1,76 @@
+#ifndef SEEN_SPIN_BUTTON_TOOL_ITEM_H
+#define SEEN_SPIN_BUTTON_TOOL_ITEM_H
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtkmm/toolitem.h>
+
+namespace Gtk {
+class RadioButtonGroup;
+class RadioMenuItem;
+}
+
+namespace Inkscape {
+namespace UI {
+namespace Widget {
+
+class SpinButton;
+
+/**
+ * \brief A spin-button with a label that can be added to a toolbar
+ */
+class SpinButtonToolItem : public Gtk::ToolItem
+{
+private:
+ Glib::ustring _name; ///< A unique ID for the widget (NOT translatable)
+ SpinButton *_btn; ///< The spin-button within the widget
+ Glib::ustring _label_text; ///< A string to use in labels for the widget (translatable)
+ double _last_val; ///< The last value of the adjustment
+ bool _transfer_focus; ///< Whether or not to transfer focus
+
+ /** A widget that grabs focus when this one loses it */
+ Gtk::Widget * _focus_widget;
+
+ // Event handlers
+ bool on_btn_focus_in_event(GdkEventFocus *focus_event);
+ bool on_btn_focus_out_event(GdkEventFocus *focus_event);
+ bool on_btn_key_press_event(GdkEventKey *key_event);
+
+ void defocus();
+ bool process_tab(int direction);
+
+ void on_numeric_menu_item_toggled(double value);
+
+ Gtk::RadioMenuItem * create_numeric_menu_item(Gtk::RadioButtonGroup *group,
+ double value);
+
+protected:
+ virtual bool on_create_menu_proxy() override;
+
+public:
+ SpinButtonToolItem(const Glib::ustring& name,
+ const Glib::ustring& label_text,
+ Glib::RefPtr<Gtk::Adjustment>& adjustment,
+ double climb_rate = 0.1,
+ double digits = 3);
+
+ void set_all_tooltip_text(const Glib::ustring& text);
+ void set_focus_widget(Gtk::Widget *widget);
+ void grab_button_focus();
+};
+} // namespace Widget
+} // namespace UI
+} // namespace Inkscape
+#endif // SEEN_SPIN_BUTTON_TOOL_ITEM_H
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp
index db0dded73..3199e25ef 100644
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
@@ -189,7 +189,7 @@ static struct {
gchar const *swatch_tool;
gchar const *swatch_tip;
} const aux_toolboxes[] = {
- { "/tools/select", "select_toolbox", nullptr, Inkscape::UI::Toolbar::SelectToolbar::prep, "SelectToolbar",
+ { "/tools/select", "select_toolbox", Inkscape::UI::Toolbar::SelectToolbar::create, nullptr, "SelectToolbar",
SP_VERB_INVALID, nullptr, nullptr},
{ "/tools/nodes", "node_toolbox", nullptr, Inkscape::UI::Toolbar::NodeToolbar::prep, "NodeToolbar",
SP_VERB_INVALID, nullptr, nullptr},