diff options
39 files changed, 1471 insertions, 3693 deletions
diff --git a/share/ui/toolbar-select.ui b/share/ui/toolbar-select.ui deleted file mode 100644 index abb3e6080..000000000 --- a/share/ui/toolbar-select.ui +++ /dev/null @@ -1,28 +0,0 @@ -<ui> - <toolbar name='TextToolbar'> - <toolitem action='TextFontFamilyAction' /> - <toolitem action='TextFontStyleAction' /> - <separator /> - <toolitem action='TextOuterStyleAction' /> - <toolitem action='TextFontSizeAction' /> - <toolitem action='TextLineHeightAction' /> - <toolitem action='TextLineHeightUnitsAction' /> - <toolitem action='TextLineHeightUnsetAction' /> - <toolitem action='TextLineSpacingAction' /> - <separator /> - <toolitem action='TextAlignAction' /> - <separator /> - <toolitem action='TextSuperscriptAction' /> - <toolitem action='TextSubscriptAction' /> - <separator /> - <toolitem action='TextLetterSpacingAction' /> - <toolitem action='TextWordSpacingAction' /> - <toolitem action='TextDxAction' /> - <toolitem action='TextDyAction' /> - <toolitem action='TextRotationAction' /> - <separator /> - <toolitem action='TextWritingModeAction' /> - <toolitem action='TextOrientationAction' /> - <toolitem action='TextDirectionAction' /> - </toolbar> -</ui> diff --git a/src/desktop.cpp b/src/desktop.cpp index 4c28cd918..ab8d70601 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -1524,10 +1524,10 @@ SPDesktop::setToolboxAdjustmentValue (gchar const* id, double val) _widget->setToolboxAdjustmentValue (id, val); } -void -SPDesktop::setToolboxSelectOneValue (gchar const* id, gint val) +Gtk::Toolbar* +SPDesktop::get_toolbar_by_name(const Glib::ustring& name) { - _widget->setToolboxSelectOneValue (id, val); + return _widget->get_toolbar_by_name(name); } bool diff --git a/src/desktop.h b/src/desktop.h index 66fad5a65..9b37754c7 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -65,7 +65,8 @@ class InkscapeWindow; namespace Gtk { - class Window; + class Toolbar; + class Window; } typedef int sp_verb_t; @@ -388,8 +389,8 @@ public: void layoutWidget(); void destroyWidget(); void setToolboxFocusTo (gchar const* label); + Gtk::Toolbar* get_toolbar_by_name(const Glib::ustring& name); void setToolboxAdjustmentValue (gchar const* id, double val); - void setToolboxSelectOneValue (gchar const* id, gint val); bool isToolboxButtonActive (gchar const *id); void updateNow(); void updateCanvasNow(); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index bf773ba6f..d4f906836 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -162,6 +162,7 @@ set(ui_SRC widget/color-scales.cpp widget/color-slider.cpp widget/color-wheel-selector.cpp + widget/combo-box-entry-tool-item.cpp widget/combo-tool-item.cpp widget/dash-selector.cpp widget/dock-item.cpp @@ -179,7 +180,6 @@ set(ui_SRC widget/imagetoggler.cpp widget/ink-color-wheel.cpp widget/ink-flow-box.cpp - widget/ink-select-one-action.cpp widget/ink-spinscale.cpp widget/insertordericon.cpp widget/label-tool-item.cpp @@ -396,6 +396,7 @@ set(ui_SRC widget/color-slider.h widget/color-wheel-selector.h widget/combo-enums.h + widget/combo-box-entry-tool-item.h widget/combo-tool-item.h widget/dash-selector.h widget/dock-item.h @@ -414,7 +415,6 @@ set(ui_SRC widget/imagetoggler.h widget/ink-color-wheel.h widget/ink-flow-box.h - widget/ink-select-one-action.h widget/ink-spinscale.h widget/label-tool-item.h widget/labelled.h diff --git a/src/ui/toolbar/arc-toolbar.h b/src/ui/toolbar/arc-toolbar.h index 08acc136b..b0b04500b 100644 --- a/src/ui/toolbar/arc-toolbar.h +++ b/src/ui/toolbar/arc-toolbar.h @@ -32,7 +32,6 @@ #include <gtkmm/adjustment.h> -class InkSelectOneAction; class SPDesktop; class SPItem; diff --git a/src/ui/toolbar/box3d-toolbar.h b/src/ui/toolbar/box3d-toolbar.h index c5970bf3b..dc74664ee 100644 --- a/src/ui/toolbar/box3d-toolbar.h +++ b/src/ui/toolbar/box3d-toolbar.h @@ -37,10 +37,6 @@ class Persp3D; class SPDesktop; -typedef struct _EgeAdjustmentAction EgeAdjustmentAction; -typedef struct _GtkActionGroup GtkActionGroup; -typedef struct _InkToggleAction InkToggleAction; - namespace Inkscape { class Selection; diff --git a/src/ui/toolbar/lpe-toolbar.cpp b/src/ui/toolbar/lpe-toolbar.cpp index 067687f02..ef5a2ce1c 100644 --- a/src/ui/toolbar/lpe-toolbar.cpp +++ b/src/ui/toolbar/lpe-toolbar.cpp @@ -173,6 +173,12 @@ LPEToolbar::LPEToolbar(SPDesktop *desktop) show_all(); } +void +LPEToolbar::set_mode(int mode) +{ + _mode_buttons[mode]->set_active(); +} + GtkWidget * LPEToolbar::create(SPDesktop *desktop) { diff --git a/src/ui/toolbar/lpe-toolbar.h b/src/ui/toolbar/lpe-toolbar.h index 1609f3915..23647a73c 100644 --- a/src/ui/toolbar/lpe-toolbar.h +++ b/src/ui/toolbar/lpe-toolbar.h @@ -92,6 +92,7 @@ protected: public: static GtkWidget * create(SPDesktop *desktop); + void set_mode(int mode); }; } diff --git a/src/ui/toolbar/rect-toolbar.h b/src/ui/toolbar/rect-toolbar.h index 3aee3b563..58d4b2c1c 100644 --- a/src/ui/toolbar/rect-toolbar.h +++ b/src/ui/toolbar/rect-toolbar.h @@ -36,10 +36,6 @@ class SPDesktop; class SPItem; class SPRect; -typedef struct _EgeAdjustmentAction EgeAdjustmentAction; -typedef struct _EgeOutputAction EgeOutputAction; -typedef struct _InkAction InkAction; - namespace Gtk { class Toolbutton; } diff --git a/src/ui/toolbar/select-toolbar.cpp b/src/ui/toolbar/select-toolbar.cpp index e405b914f..87682b127 100644 --- a/src/ui/toolbar/select-toolbar.cpp +++ b/src/ui/toolbar/select-toolbar.cpp @@ -37,7 +37,6 @@ #include "ui/icon-names.h" #include "ui/widget/combo-tool-item.h" -#include "ui/widget/ink-select-one-action.h" #include "ui/widget/spin-button-tool-item.h" #include "ui/widget/unit-tracker.h" diff --git a/src/ui/toolbar/spray-toolbar.cpp b/src/ui/toolbar/spray-toolbar.cpp index 620351a99..9e7c4e820 100644 --- a/src/ui/toolbar/spray-toolbar.cpp +++ b/src/ui/toolbar/spray-toolbar.cpp @@ -528,6 +528,12 @@ SprayToolbar::on_pref_toggled(Gtk::ToggleToolButton *btn, prefs->setBool(path, active); } +void +SprayToolbar::set_mode(int mode) +{ + _mode_buttons[mode]->set_active(); +} + } } } diff --git a/src/ui/toolbar/spray-toolbar.h b/src/ui/toolbar/spray-toolbar.h index 8c8d9172b..4587cf033 100644 --- a/src/ui/toolbar/spray-toolbar.h +++ b/src/ui/toolbar/spray-toolbar.h @@ -97,6 +97,8 @@ protected: public: static GtkWidget * create(SPDesktop *desktop); + + void set_mode(int mode); }; } } diff --git a/src/ui/toolbar/text-toolbar.cpp b/src/ui/toolbar/text-toolbar.cpp index 3b55f8b08..8e747cb39 100644 --- a/src/ui/toolbar/text-toolbar.cpp +++ b/src/ui/toolbar/text-toolbar.cpp @@ -35,8 +35,6 @@ #include "desktop.h" #include "document-undo.h" #include "document.h" -#include "widgets/ink-toggle-action.h" -#include "widgets/toolbox.h" #include "inkscape.h" #include "selection-chemistry.h" #include "text-editing.h" @@ -55,15 +53,14 @@ #include "ui/icon-names.h" #include "ui/tools/text-tool.h" -#include "ui/widget/ink-select-one-action.h" +#include "ui/widget/combo-box-entry-tool-item.h" +#include "ui/widget/combo-tool-item.h" +#include "ui/widget/spin-button-tool-item.h" #include "ui/widget/unit-tracker.h" -#include "widgets/ege-adjustment-action.h" -#include "widgets/ink-comboboxentry-action.h" #include "widgets/style-utils.h" using Inkscape::DocumentUndo; -using Inkscape::UI::ToolboxFactory; using Inkscape::Util::Unit; using Inkscape::Util::Quantity; using Inkscape::Util::unit_table; @@ -270,16 +267,8 @@ TextToolbar::TextToolbar(SPDesktop *desktop) _tracker->addUnit(unit_table.getUnit("em")); _tracker->addUnit(unit_table.getUnit("ex")); _tracker->setActiveUnit(unit_table.getUnit("%")); -} - -// Define all the "widgets" in the toolbar. -GtkWidget * -TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) -{ - auto toolbar = new TextToolbar(desktop); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - GtkIconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); /* Font family */ { @@ -289,31 +278,30 @@ TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) Glib::RefPtr<Gtk::ListStore> store = fontlister->get_font_list(); GtkListStore* model = store->gobj(); - toolbar->_font_family_action = - ink_comboboxentry_action_new( "TextFontFamilyAction", - _("Font Family"), - _("Select Font Family (Alt-X to access)"), - nullptr, - GTK_TREE_MODEL(model), - -1, // Entry width - 50, // Extra list width - (gpointer)font_lister_cell_data_func2, // Cell layout - (gpointer)font_lister_separator_func2, - GTK_WIDGET(desktop->canvas)); // Focus widget - ink_comboboxentry_action_popup_enable( toolbar->_font_family_action ); // Enable entry completion + _font_family_item = + Gtk::manage(new UI::Widget::ComboBoxEntryToolItem( "TextFontFamilyAction", + _("Font Family"), + _("Select Font Family (Alt-X to access)"), + GTK_TREE_MODEL(model), + -1, // Entry width + 50, // Extra list width + (gpointer)font_lister_cell_data_func2, // Cell layout + (gpointer)font_lister_separator_func2, + GTK_WIDGET(desktop->canvas))); // Focus widget + _font_family_item->popup_enable(); // Enable entry completion gchar *const info = _("Select all text with this font-family"); - ink_comboboxentry_action_set_info( toolbar->_font_family_action, info ); // Show selection icon - ink_comboboxentry_action_set_info_cb( toolbar->_font_family_action, (gpointer)sp_text_toolbox_select_cb ); + _font_family_item->set_info( info ); // Show selection icon + _font_family_item->set_info_cb( (gpointer)sp_text_toolbox_select_cb ); gchar *const warning = _("Font not found on system"); - ink_comboboxentry_action_set_warning( toolbar->_font_family_action, warning ); // Show icon w/ tooltip if font missing - ink_comboboxentry_action_set_warning_cb( toolbar->_font_family_action, (gpointer)sp_text_toolbox_select_cb ); + _font_family_item->set_warning( warning ); // Show icon w/ tooltip if font missing + _font_family_item->set_warning_cb( (gpointer)sp_text_toolbox_select_cb ); //ink_comboboxentry_action_set_warning_callback( act, sp_text_fontfamily_select_all ); - ink_comboboxentry_action_set_altx_name( toolbar->_font_family_action, "altx-text" ); // Set Alt-X keyboard shortcut - g_signal_connect( G_OBJECT(toolbar->_font_family_action), "changed", G_CALLBACK(fontfamily_value_changed), (gpointer)toolbar ); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_font_family_action) ); + _font_family_item->set_altx_name( "altx-text" ); // Set Alt-X keyboard shortcut + _font_family_item->signal_changed().connect( sigc::mem_fun(*this, &TextToolbar::fontfamily_value_changed) ); + add(*_font_family_item); // Change style of drop-down from menu to list auto css_provider = gtk_css_provider_new(); @@ -329,6 +317,39 @@ TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) GTK_STYLE_PROVIDER_PRIORITY_USER); } + /* Font styles */ + { + Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); + Glib::RefPtr<Gtk::ListStore> store = fontlister->get_style_list(); + GtkListStore* model_style = store->gobj(); + + _font_style_item = Gtk::manage(new UI::Widget::ComboBoxEntryToolItem( "TextFontStyleAction", + _("Font Style"), + _("Font style"), + GTK_TREE_MODEL(model_style), + 12, // Width in characters + 0, // Extra list width + nullptr, // Cell layout + nullptr, // Separator + GTK_WIDGET(desktop->canvas))); // Focus widget + + _font_style_item->signal_changed().connect(sigc::mem_fun(*this, &TextToolbar::fontstyle_value_changed)); + add(*_font_style_item); + } + + add_separator(); + + /* Text outer style */ + { + _outer_style_item = Gtk::manage(new Gtk::ToggleToolButton()); + _outer_style_item->set_label(_("Show outer style")); + _outer_style_item->set_tooltip_text(_("Show style of outermost text element. The 'font-size' and 'line-height' values of the outermost text element determine the minimum line spacing in the block.")); + _outer_style_item->set_icon_name(INKSCAPE_ICON("text_outer_style")); + add(*_outer_style_item); + _outer_style_item->signal_toggled().connect(sigc::mem_fun(*this, &TextToolbar::outer_style_changed)); + _outer_style_item->set_active(prefs->getBool("/tools/text/outer_style", false)); + } + /* Font size */ { // List of font sizes for drop-down menu @@ -338,71 +359,111 @@ TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) sp_text_set_sizes(model_size, unit); - Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", sp_style_get_css_unit_string(unit), ")"); + auto unit_str = sp_style_get_css_unit_string(unit); + Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", unit_str, ")"); - toolbar->_font_size_action = ink_comboboxentry_action_new( "TextFontSizeAction", - _("Font Size"), - _(tooltip.c_str()), - nullptr, - GTK_TREE_MODEL(model_size), - 8, // Width in characters - 0, // Extra list width - nullptr, // Cell layout - nullptr, // Separator - GTK_WIDGET(desktop->canvas)); // Focus widget + _font_size_item = Gtk::manage(new UI::Widget::ComboBoxEntryToolItem( "TextFontSizeAction", + _("Font Size"), + tooltip, + GTK_TREE_MODEL(model_size), + 8, // Width in characters + 0, // Extra list width + nullptr, // Cell layout + nullptr, // Separator + GTK_WIDGET(desktop->canvas))); // Focus widget - g_signal_connect( G_OBJECT(toolbar->_font_size_action), "changed", G_CALLBACK(fontsize_value_changed), (gpointer)toolbar ); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_font_size_action) ); + _font_size_item->signal_changed().connect(sigc::mem_fun(*this, &TextToolbar::fontsize_value_changed)); + add(*_font_size_item); } - /* Font styles */ + /* Line height */ { - Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); - Glib::RefPtr<Gtk::ListStore> store = fontlister->get_style_list(); - GtkListStore* model_style = store->gobj(); - - toolbar->_font_style_action = ink_comboboxentry_action_new( "TextFontStyleAction", - _("Font Style"), - _("Font style"), - nullptr, - GTK_TREE_MODEL(model_style), - 12, // Width in characters - 0, // Extra list width - nullptr, // Cell layout - nullptr, // Separator - GTK_WIDGET(desktop->canvas)); // Focus widget + // Drop down menu + std::vector<Glib::ustring> labels = {_("Smaller spacing"), "", "", "", "", C_("Text tool", "Normal"), "", "", "", "", "", _("Larger spacing")}; + std::vector<double> values = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 2.0}; + + auto line_height_val = prefs->getDouble("/tools/text/lineheight", 0.0); + _line_height_adj = Gtk::Adjustment::create(line_height_val, 0.0, 1000.0, 0.1, 1.0); + _line_height_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("text-line-height", _("Line:"), _line_height_adj, 0.1, 2)); + _line_height_item->set_tooltip_text(_("Spacing between baselines")); + _line_height_item->set_custom_numeric_menu_data(values, labels); + _line_height_item->set_focus_widget(Glib::wrap(GTK_WIDGET(desktop->canvas))); + _line_height_adj->signal_value_changed().connect(sigc::mem_fun(*this, &TextToolbar::lineheight_value_changed)); + //_tracker->addAdjustment(_line_height_adj->gobj()); // (Alex V) Why is this commented out? + add(*_line_height_item); + _line_height_item->set_sensitive(true); + _line_height_item->set_icon(INKSCAPE_ICON("text_line_spacing")); + } - g_signal_connect( G_OBJECT(toolbar->_font_style_action), "changed", G_CALLBACK(fontstyle_value_changed), (gpointer)toolbar ); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_font_style_action) ); + /* Line height units */ + { + _line_height_units_item = _tracker->create_tool_item( _("Units"), ("") ); + add(*_line_height_units_item); + _line_height_units_item->signal_changed_after().connect(sigc::mem_fun(*this, &TextToolbar::lineheight_unit_changed)); } - /* Style - Superscript */ + /* Text line height unset */ { - toolbar->_superscript_action = ink_toggle_action_new( "TextSuperscriptAction", // Name - _("Toggle Superscript"), // Label - _("Toggle superscript"), // Tooltip - "text_superscript", // Icon (inkId) - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_superscript_action ) ); - g_signal_connect_after( G_OBJECT(toolbar->_superscript_action), "toggled", G_CALLBACK(script_changed), toolbar ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(toolbar->_superscript_action), prefs->getBool("/tools/text/super", false) ); + _line_height_unset_item = Gtk::manage(new Gtk::ToggleToolButton()); + _line_height_unset_item->set_label(_("Unset line height")); + _line_height_unset_item->set_tooltip_text(_("If enabled, line height is set on part of selection. Click to unset.")); + _line_height_unset_item->set_icon_name(INKSCAPE_ICON("paint-unknown")); + add(*_line_height_unset_item); + _line_height_unset_item->signal_toggled().connect(sigc::mem_fun(*this, &TextToolbar::lineheight_unset_changed)); + _line_height_unset_item->set_active(prefs->getBool("/tools/text/line_height_unset", false)); } - /* Style - Subscript */ + /* Line spacing mode */ { - toolbar->_subscript_action = ink_toggle_action_new( "TextSubscriptAction", // Name - _("Toggle Subscript"), // Label - _("Toggle subscript"), // Tooltip - "text_subscript", // Icon (inkId) - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_subscript_action ) ); - g_signal_connect_after( G_OBJECT(toolbar->_subscript_action), "toggled", G_CALLBACK(script_changed), (gpointer)toolbar ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(toolbar->_subscript_action), prefs->getBool("/tools/text/sub", false) ); + UI::Widget::ComboToolItemColumns columns; + + Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns); + + Gtk::TreeModel::Row row; + + row = *(store->append()); + row[columns.col_label ] = _("Adaptive"); + row[columns.col_tooltip ] = _("Line spacing adapts to font size."); + row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); + row[columns.col_sensitive] = true; + + row = *(store->append()); + row[columns.col_label ] = _("Minimum"); + row[columns.col_tooltip ] = _("Line spacing adapts to fonts size with set minimum spacing."); + row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); + row[columns.col_sensitive] = true; + row = *(store->append()); + row[columns.col_label ] = _("Even"); + row[columns.col_tooltip ] = _("Lines evenly spaced."); + row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); + row[columns.col_sensitive] = true; + + row = *(store->append()); + row[columns.col_label ] = _("Adjustable ☠"); + row[columns.col_tooltip ] = _("Line spacing fully adjustable"); + row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); + row[columns.col_sensitive] = true; + + _line_spacing_item = + UI::Widget::ComboToolItem::create(_("Line Spacing Mode"), // Label + _("How should multiple baselines be spaced?\n Adaptive: Line spacing adapts to font size.\n Minimum: Like Adaptive, but with a set minimum.\n Even: Evenly spaced.\n Adjustable: No restrictions."), // Tooltip + "Not Used", // Icon + store ); // Tree store + _line_spacing_item->use_icon(true); + _line_spacing_item->use_label(true); + gint mode = prefs->getInt("/tools/text/line_spacing_mode", 0); + _line_spacing_item->set_active( mode ); + + add(*_line_spacing_item); + + _line_spacing_item->signal_changed().connect(sigc::mem_fun(*this, &TextToolbar::line_spacing_mode_changed)); } + add_separator(); + /* Alignment */ { - InkSelectOneActionColumns columns; + UI::Widget::ComboToolItemColumns columns; Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns); @@ -432,25 +493,135 @@ TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) row[columns.col_icon ] = INKSCAPE_ICON("format-justify-fill"); row[columns.col_sensitive] = false; - toolbar->_align_action = - InkSelectOneAction::create( "TextAlignAction", // Name - _("Alignment"), // Label - _("Text alignment"), // Tooltip - "Not Used", // Icon - store ); // Tree store - toolbar->_align_action->use_radio( false ); - toolbar->_align_action->use_label( false ); + _align_item = + UI::Widget::ComboToolItem::create(_("Alignment"), // Label + _("Text alignment"), // Tooltip + "Not Used", // Icon + store ); // Tree store + _align_item->use_icon( true ); + _align_item->use_label( false ); gint mode = prefs->getInt("/tools/text/align_mode", 0); - toolbar->_align_action->set_active( mode ); + _align_item->set_active( mode ); - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_align_action->gobj() )); + add(*_align_item); - toolbar->_align_action->signal_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::align_mode_changed)); + _align_item->signal_changed().connect(sigc::mem_fun(*this, &TextToolbar::align_mode_changed)); } + add_separator(); + + /* Style - Superscript */ + { + _superscript_item = Gtk::manage(new Gtk::ToggleToolButton()); + _superscript_item->set_label(_("Toggle superscript")); + _superscript_item->set_tooltip_text(_("Toggle superscript")); + _superscript_item->set_icon_name(INKSCAPE_ICON("text_superscript")); + _superscript_item->set_name("text-superscript"); + add(*_superscript_item); + _superscript_item->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &TextToolbar::script_changed), _superscript_item)); + _superscript_item->set_active(prefs->getBool("/tools/text/super", false)); + } + + /* Style - Subscript */ + { + _subscript_item = Gtk::manage(new Gtk::ToggleToolButton()); + _subscript_item->set_label(_("Toggle subscript")); + _subscript_item->set_tooltip_text(_("Toggle subscript")); + _subscript_item->set_icon_name(INKSCAPE_ICON("text_subscript")); + _subscript_item->set_name("text-subscript"); + add(*_subscript_item); + _subscript_item->signal_toggled().connect(sigc::bind(sigc::mem_fun(*this, &TextToolbar::script_changed), _subscript_item)); + _subscript_item->set_active(prefs->getBool("/tools/text/sub", false)); + } + + add_separator(); + + /* Letter spacing */ + { + // Drop down menu + std::vector<Glib::ustring> labels = {_("Negative spacing"), "", "", "", C_("Text tool", "Normal"), "", "", "", "", "", "", "", _("Positive spacing")}; + std::vector<double> values = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; + auto letter_spacing_val = prefs->getDouble("/tools/text/letterspacing", 0.0); + _letter_spacing_adj = Gtk::Adjustment::create(letter_spacing_val, -100.0, 100.0, 0.01, 0.10); + _letter_spacing_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("text-letter-spacing", _("Letter:"), _letter_spacing_adj, 0.1, 2)); + _letter_spacing_item->set_tooltip_text(_("Spacing between letters (px)")); + _letter_spacing_item->set_custom_numeric_menu_data(values, labels); + _letter_spacing_item->set_focus_widget(Glib::wrap(GTK_WIDGET(desktop->canvas))); + _letter_spacing_adj->signal_value_changed().connect(sigc::mem_fun(*this, &TextToolbar::letterspacing_value_changed)); + add(*_letter_spacing_item); + _letter_spacing_item->set_sensitive(true); + _letter_spacing_item->set_icon(INKSCAPE_ICON("text_letter_spacing")); + } + + /* Word spacing */ + { + // Drop down menu + std::vector<Glib::ustring> labels = {_("Negative spacing"), "", "", "", C_("Text tool", "Normal"), "", "", "", "", "", "", "", _("Positive spacing")}; + std::vector<double> values = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; + auto word_spacing_val = prefs->getDouble("/tools/text/wordspacing", 0.0); + _word_spacing_adj = Gtk::Adjustment::create(word_spacing_val, -100.0, 100.0, 0.01, 0.10); + _word_spacing_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("text-word-spacing", _("Word:"), _word_spacing_adj, 0.1, 2)); + _word_spacing_item->set_tooltip_text(_("Spacing between words (px)")); + _word_spacing_item->set_custom_numeric_menu_data(values, labels); + _word_spacing_item->set_focus_widget(Glib::wrap(GTK_WIDGET(desktop->canvas))); + _word_spacing_adj->signal_value_changed().connect(sigc::mem_fun(*this, &TextToolbar::wordspacing_value_changed)); + add(*_word_spacing_item); + _word_spacing_item->set_sensitive(true); + _word_spacing_item->set_icon(INKSCAPE_ICON("text_word_spacing")); + } + + /* Character kerning (horizontal shift) */ + { + // Drop down menu + std::vector<double> values = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; + auto dx_val = prefs->getDouble("/tools/text/dx", 0.0); + _dx_adj = Gtk::Adjustment::create(dx_val, -100.0, 100.0, 0.01, 0.1); + _dx_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("text-dx", _("Kern:"), _dx_adj, 0.1, 2)); + _dx_item->set_custom_numeric_menu_data(values); + _dx_item->set_tooltip_text(_("Horizontal kerning (px)")); + _dx_item->set_focus_widget(Glib::wrap(GTK_WIDGET(desktop->canvas))); + _dx_adj->signal_value_changed().connect(sigc::mem_fun(*this, &TextToolbar::dx_value_changed)); + add(*_dx_item); + _dx_item->set_sensitive(true); + _dx_item->set_icon(INKSCAPE_ICON("text_horz_kern")); + } + + /* Character vertical shift */ + { + // Drop down menu + std::vector<double> values = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; + auto dy_val = prefs->getDouble("/tools/text/dy", 0.0); + _dy_adj = Gtk::Adjustment::create(dy_val, -100.0, 100.0, 0.01, 0.1); + _dy_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("text-dy", _("Vert:"), _dy_adj, 0.1, 2)); + _dy_item->set_tooltip_text(_("Vertical kerning (px)")); + _dy_item->set_custom_numeric_menu_data(values); + _dy_item->set_focus_widget(Glib::wrap(GTK_WIDGET(desktop->canvas))); + _dy_adj->signal_value_changed().connect(sigc::mem_fun(*this, &TextToolbar::dy_value_changed)); + _dy_item->set_sensitive(true); + _dy_item->set_icon(INKSCAPE_ICON("text_vert_kern")); + add(*_dy_item); + } + + /* Character rotation */ + { + std::vector<double> values = { -90, -45, -30, -15, 0, 15, 30, 45, 90, 180 }; + auto rotation_val = prefs->getDouble("/tools/text/rotation", 0.0); + _rotation_adj = Gtk::Adjustment::create(rotation_val, -180.0, 180.0, 0.1, 1.0); + _rotation_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("text-rotation", _("Rot:"), _rotation_adj, 0.1, 2)); + _rotation_item->set_tooltip_text(_("Character rotation (degrees)")); + _rotation_item->set_custom_numeric_menu_data(values); + _rotation_item->set_focus_widget(Glib::wrap(GTK_WIDGET(desktop->canvas))); + _rotation_adj->signal_value_changed().connect(sigc::mem_fun(*this, &TextToolbar::rotation_value_changed)); + _rotation_item->set_sensitive(); + _rotation_item->set_icon(INKSCAPE_ICON("text_rotation")); + add(*_rotation_item); + } + + add_separator(); + /* Writing mode (Horizontal, Vertical-LR, Vertical-RL) */ { - InkSelectOneActionColumns columns; + UI::Widget::ComboToolItemColumns columns; Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns); @@ -474,25 +645,25 @@ TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) row[columns.col_icon ] = INKSCAPE_ICON("format-text-direction-vertical-lr"); row[columns.col_sensitive] = true; - toolbar->_writing_mode_action = - InkSelectOneAction::create( "TextWritingModeAction", // Name - _("Writing mode"), // Label - _("Block progression"), // Tooltip - "Not Used", // Icon - store ); // Tree store - toolbar->_writing_mode_action->use_radio( false ); - toolbar->_writing_mode_action->use_label( false ); + _writing_mode_item = + UI::Widget::ComboToolItem::create( _("Writing mode"), // Label + _("Block progression"), // Tooltip + "Not Used", // Icon + store ); // Tree store + _writing_mode_item->use_icon(true); + _writing_mode_item->use_label( false ); gint mode = prefs->getInt("/tools/text/writing_mode", 0); - toolbar->_writing_mode_action->set_active( mode ); + _writing_mode_item->set_active( mode ); - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_writing_mode_action->gobj() )); + add(*_writing_mode_item); - toolbar->_writing_mode_action->signal_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::writing_mode_changed)); + _writing_mode_item->signal_changed().connect(sigc::mem_fun(*this, &TextToolbar::writing_mode_changed)); } + /* Text (glyph) orientation (Auto (mixed), Upright, Sideways) */ { - InkSelectOneActionColumns columns; + UI::Widget::ComboToolItemColumns columns; Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns); @@ -516,25 +687,24 @@ TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) row[columns.col_icon ] = INKSCAPE_ICON("text-orientation-sideways"); row[columns.col_sensitive] = true; - toolbar->_orientation_action = - InkSelectOneAction::create( "TextOrientationAction", // Name - _("Text orientation"), // Label - _("Text (glyph) orientation in vertical text."), // Tooltip - "Not Used", // Icon - store ); // List store - toolbar->_orientation_action->use_radio( false ); - toolbar->_orientation_action->use_label( false ); + _orientation_item = + UI::Widget::ComboToolItem::create(_("Text orientation"), // Label + _("Text (glyph) orientation in vertical text."), // Tooltip + "Not Used", // Icon + store ); // List store + _orientation_item->use_icon(true); + _orientation_item->use_label( false ); gint mode = prefs->getInt("/tools/text/text_orientation", 0); - toolbar->_orientation_action->set_active( mode ); + _orientation_item->set_active( mode ); - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_orientation_action->gobj() )); + add(*_orientation_item); - toolbar->_orientation_action->signal_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::orientation_changed)); + _orientation_item->signal_changed().connect(sigc::mem_fun(*this, &TextToolbar::orientation_changed)); } // Text direction (predominant direction of horizontal text). { - InkSelectOneActionColumns columns; + UI::Widget::ComboToolItemColumns columns; Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns); @@ -552,299 +722,31 @@ TextToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) row[columns.col_icon ] = INKSCAPE_ICON("format-text-direction-r2l"); row[columns.col_sensitive] = true; - toolbar->_direction_action = - InkSelectOneAction::create( "TextDirectionAction", // Name - _("Text direction"), // Label - _("Text direction for normally horizontal text."), // Tooltip - "Not Used", // Icon - store ); // List store - toolbar->_direction_action->use_radio( false ); - toolbar->_direction_action->use_label( false ); + _direction_item = + UI::Widget::ComboToolItem::create( _("Text direction"), // Label + _("Text direction for normally horizontal text."), // Tooltip + "Not Used", // Icon + store ); // List store + _direction_item->use_icon(true); + _direction_item->use_label(false); gint mode = prefs->getInt("/tools/text/text_direction", 0); - toolbar->_direction_action->set_active( mode ); - - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_direction_action->gobj() )); + _direction_item->set_active( mode ); - toolbar->_direction_action->signal_changed_after().connect(sigc::mem_fun(*toolbar, &TextToolbar::direction_changed)); + add(*_direction_item); + _direction_item->signal_changed_after().connect(sigc::mem_fun(*this, &TextToolbar::direction_changed)); } - /* Line height */ - { - // Drop down menu - gchar const* labels[] = {_("Smaller spacing"), nullptr, nullptr, nullptr, nullptr, C_("Text tool", "Normal"), nullptr, nullptr, nullptr, nullptr, nullptr, _("Larger spacing")}; - gdouble values[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1,2, 1.3, 1.4, 1.5, 2.0}; - - toolbar->_line_height_action = create_adjustment_action( - "TextLineHeightAction", /* name */ - _("Line Height"), /* label */ - _("Line:"), /* short label */ - _("Spacing between baselines"), /* tooltip */ - "/tools/text/lineheight", /* preferences path */ - 0.0, /* default */ - FALSE, /* set alt-x keyboard shortcut? */ - nullptr, /* altx_mark */ - 0.0, 1000.0, 0.1, 1.0, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - nullptr, // tracker, /* unit tracker */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - ege_adjustment_action_set_focuswidget(toolbar->_line_height_action, GTK_WIDGET(desktop->canvas)); - - toolbar->_line_height_adj = Glib::wrap(ege_adjustment_action_get_adjustment(toolbar->_line_height_action)); - toolbar->_line_height_adj->signal_value_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::lineheight_value_changed)); - - //tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_line_height_action) ); - gtk_action_set_sensitive( GTK_ACTION(toolbar->_line_height_action), TRUE ); - - // TODO: Create accessor method for this, instead of GObject property - g_object_set( G_OBJECT(toolbar->_line_height_action), "iconId", "text_line_spacing", NULL ); - } - - /* Line height units */ - { - toolbar->_line_height_units_action = toolbar->_tracker->createAction( "TextLineHeightUnitsAction", _("Units"), ("") ); - gtk_action_group_add_action( mainActions, toolbar->_line_height_units_action->gobj() ); - toolbar->_line_height_units_action->signal_changed_after().connect(sigc::mem_fun(*toolbar, &TextToolbar::lineheight_unit_changed)); - } - - /* Line spacing mode */ - { - InkSelectOneActionColumns columns; - - Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns); - - Gtk::TreeModel::Row row; - - row = *(store->append()); - row[columns.col_label ] = _("Adaptive"); - row[columns.col_tooltip ] = _("Line spacing adapts to font size."); - row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); - row[columns.col_sensitive] = true; - - row = *(store->append()); - row[columns.col_label ] = _("Minimum"); - row[columns.col_tooltip ] = _("Line spacing adapts to fonts size with set minimum spacing."); - row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); - row[columns.col_sensitive] = true; - row = *(store->append()); - row[columns.col_label ] = _("Even"); - row[columns.col_tooltip ] = _("Lines evenly spaced."); - row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); - row[columns.col_sensitive] = true; - - row = *(store->append()); - row[columns.col_label ] = _("Adjustable ☠"); - row[columns.col_tooltip ] = _("Line spacing fully adjustable"); - row[columns.col_icon ] = INKSCAPE_ICON("text_line_spacing"); - row[columns.col_sensitive] = true; - - toolbar->_line_spacing_action = - InkSelectOneAction::create( "TextLineSpacingAction", // Name - _("Line Spacing Mode"), // Label - _("How should multiple baselines be spaced?\n Adaptive: Line spacing adapts to font size.\n Minimum: Like Adaptive, but with a set minimum.\n Even: Evenly spaced.\n Adjustable: No restrictions."), // Tooltip - "Not Used", // Icon - store ); // Tree store - toolbar->_line_spacing_action->use_radio( false ); - toolbar->_line_spacing_action->use_label( true ); - gint mode = prefs->getInt("/tools/text/line_spacing_mode", 0); - toolbar->_line_spacing_action->set_active( mode ); - - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_line_spacing_action->gobj() )); - - toolbar->_line_spacing_action->signal_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::line_spacing_mode_changed)); - } - - /* Word spacing */ - { - // Drop down menu - gchar const* labels[] = {_("Negative spacing"), nullptr, nullptr, nullptr, C_("Text tool", "Normal"), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, _("Positive spacing")}; - gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; - - toolbar->_word_spacing_action = create_adjustment_action( - "TextWordSpacingAction", /* name */ - _("Word spacing"), /* label */ - _("Word:"), /* short label */ - _("Spacing between words (px)"), /* tooltip */ - "/tools/text/wordspacing", /* preferences path */ - 0.0, /* default */ - FALSE, /* set alt-x keyboard shortcut? */ - nullptr, /* altx_mark */ - -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - nullptr, /* unit tracker */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - ege_adjustment_action_set_focuswidget(toolbar->_word_spacing_action, GTK_WIDGET(desktop->canvas)); - - toolbar->_word_spacing_adj = Glib::wrap(ege_adjustment_action_get_adjustment(toolbar->_word_spacing_action)); - toolbar->_word_spacing_adj->signal_value_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::wordspacing_value_changed)); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_word_spacing_action) ); - gtk_action_set_sensitive( GTK_ACTION(toolbar->_word_spacing_action), TRUE ); - g_object_set( G_OBJECT(toolbar->_word_spacing_action), "iconId", "text_word_spacing", NULL ); - } - - /* Letter spacing */ - { - // Drop down menu - gchar const* labels[] = {_("Negative spacing"), nullptr, nullptr, nullptr, C_("Text tool", "Normal"), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, _("Positive spacing")}; - gdouble values[] = {-2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0}; - - toolbar->_letter_spacing_action = create_adjustment_action( - "TextLetterSpacingAction", /* name */ - _("Letter spacing"), /* label */ - _("Letter:"), /* short label */ - _("Spacing between letters (px)"), /* tooltip */ - "/tools/text/letterspacing", /* preferences path */ - 0.0, /* default */ - FALSE, /* set alt-x keyboard shortcut? */ - nullptr, /* altx_mark */ - -100.0, 100.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - nullptr, /* unit tracker */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - ege_adjustment_action_set_focuswidget(toolbar->_letter_spacing_action, GTK_WIDGET(desktop->canvas)); - toolbar->_letter_spacing_adj = Glib::wrap(ege_adjustment_action_get_adjustment(toolbar->_letter_spacing_action)); - toolbar->_letter_spacing_adj->signal_value_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::letterspacing_value_changed)); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_letter_spacing_action) ); - gtk_action_set_sensitive( GTK_ACTION(toolbar->_letter_spacing_action), TRUE ); - g_object_set( G_OBJECT(toolbar->_letter_spacing_action), "iconId", "text_letter_spacing", NULL ); - } - - /* Character kerning (horizontal shift) */ - { - // Drop down menu - gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - gdouble values[] = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; - - toolbar->_dx_action = create_adjustment_action( - "TextDxAction", /* name */ - _("Kerning"), /* label */ - _("Kern:"), /* short label */ - _("Horizontal kerning (px)"), /* tooltip */ - "/tools/text/dx", /* preferences path */ - 0.0, /* default */ - FALSE, /* set alt-x keyboard shortcut? */ - nullptr, /* altx_mark */ - -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - nullptr, /* unit tracker */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - ege_adjustment_action_set_focuswidget(toolbar->_dx_action, GTK_WIDGET(desktop->canvas)); - toolbar->_dx_adj = Glib::wrap(ege_adjustment_action_get_adjustment(toolbar->_dx_action)); - toolbar->_dx_adj->signal_value_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::dx_value_changed)); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_dx_action) ); - gtk_action_set_sensitive( GTK_ACTION(toolbar->_dx_action), TRUE ); - g_object_set( G_OBJECT(toolbar->_dx_action), "iconId", "text_horz_kern", NULL ); - } - - /* Character vertical shift */ - { - // Drop down menu - gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - gdouble values[] = { -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0, 2.5 }; - - toolbar->_dy_action = create_adjustment_action( - "TextDyAction", /* name */ - _("Vertical Shift"), /* label */ - _("Vert:"), /* short label */ - _("Vertical shift (px)"), /* tooltip */ - "/tools/text/dy", /* preferences path */ - 0.0, /* default */ - FALSE, /* set alt-x keyboard shortcut? */ - nullptr, /* altx_mark */ - -100.0, 100.0, 0.01, 0.1, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - nullptr, /* unit tracker */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - ege_adjustment_action_set_focuswidget(toolbar->_dy_action, GTK_WIDGET(desktop->canvas)); - toolbar->_dy_adj = Glib::wrap(ege_adjustment_action_get_adjustment(toolbar->_dy_action)); - toolbar->_dy_adj->signal_value_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::dy_value_changed)); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_dy_action) ); - gtk_action_set_sensitive( GTK_ACTION(toolbar->_dy_action), TRUE ); - g_object_set( G_OBJECT(toolbar->_dy_action), "iconId", "text_vert_kern", NULL ); - } - - /* Character rotation */ - { - // Drop down menu - gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - gdouble values[] = { -90, -45, -30, -15, 0, 15, 30, 45, 90, 180 }; - - toolbar->_rotation_action = create_adjustment_action( - "TextRotationAction", /* name */ - _("Letter rotation"), /* label */ - _("Rot:"), /* short label */ - _("Character rotation (degrees)"), /* tooltip */ - "/tools/text/rotation", /* preferences path */ - 0.0, /* default */ - FALSE, /* set alt-x keyboard shortcut? */ - nullptr, /* altx_mark */ - -180.0, 180.0, 0.1, 1.0, /* lower, upper, step (arrow up/down), page up/down */ - labels, values, G_N_ELEMENTS(labels), /* drop down menu */ - nullptr, /* unit tracker */ - 0.1, /* step (used?) */ - 2, /* digits to show */ - 1.0 /* factor (multiplies default) */ - ); - ege_adjustment_action_set_focuswidget(toolbar->_rotation_action, GTK_WIDGET(desktop->canvas)); - toolbar->_rotation_adj = Glib::wrap(ege_adjustment_action_get_adjustment(toolbar->_rotation_action)); - toolbar->_rotation_adj->signal_value_changed().connect(sigc::mem_fun(*toolbar, &TextToolbar::rotation_value_changed)); - gtk_action_group_add_action( mainActions, GTK_ACTION(toolbar->_rotation_action) ); - gtk_action_set_sensitive( GTK_ACTION(toolbar->_rotation_action), TRUE ); - g_object_set( G_OBJECT(toolbar->_rotation_action), "iconId", "text_rotation", NULL ); - } - - /* Text line height unset */ - { - toolbar->_line_height_unset_action = ink_toggle_action_new( "TextLineHeightUnsetAction", // Name - _("Unset line height"), // Label - _("If enabled, line height is set on part of selection. Click to unset."), - INKSCAPE_ICON("paint-unknown"), - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_line_height_unset_action ) ); - g_signal_connect_after( G_OBJECT(toolbar->_line_height_unset_action), "toggled", G_CALLBACK(lineheight_unset_changed), (gpointer)toolbar ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(toolbar->_line_height_unset_action), prefs->getBool("/tools/text/line_height_unset", false) ); - } - - /* Text outer style */ - { - toolbar->_outer_style_action = ink_toggle_action_new( "TextOuterStyleAction", // Name - _("Show outer style"), // Label - _("Show style of outermost text element. The 'font-size' and 'line-height' values of the outermost text element determine the minimum line spacing in the block."), - INKSCAPE_ICON("text_outer_style"), - secondarySize ); // Icon size - gtk_action_group_add_action( mainActions, GTK_ACTION( toolbar->_outer_style_action ) ); - g_signal_connect_after( G_OBJECT(toolbar->_outer_style_action), "toggled", G_CALLBACK(outer_style_changed), (gpointer)toolbar ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(toolbar->_outer_style_action), prefs->getBool("/tools/text/outer_style", false) ); - } + show_all(); // Is this necessary to call? Shouldn't hurt. - toolbar->selection_changed(desktop->getSelection()); + selection_changed(desktop->getSelection()); - desktop->connectEventContextChanged(sigc::mem_fun(*toolbar, &TextToolbar::watch_ec)); - - return GTK_WIDGET(toolbar->gobj()); + desktop->connectEventContextChanged(sigc::mem_fun(*this, &TextToolbar::watch_ec)); } void -TextToolbar::fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, gpointer data ) +TextToolbar::fontfamily_value_changed() { - auto toolbar = reinterpret_cast<TextToolbar *>(data); - #ifdef DEBUG_TEXT std::cout << std::endl; std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" << std::endl; @@ -852,16 +754,16 @@ TextToolbar::fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, gpointer d #endif // quit if run by the _changed callbacks - if (toolbar->_freeze) { + if (_freeze) { #ifdef DEBUG_TEXT std::cout << "sp_text_fontfamily_value_changed: frozen... return" << std::endl; std::cout << "MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n" << std::endl; #endif return; } - toolbar->_freeze = true; + _freeze = true; - Glib::ustring new_family = ink_comboboxentry_action_get_active_text( act ); + Glib::ustring new_family = _font_family_item->get_active_text(); css_font_family_unquote( new_family ); // Remove quotes around font family names. // TODO: Think about how to handle handle multiple selections. While @@ -877,13 +779,16 @@ TextToolbar::fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, gpointer d if( new_family.compare( fontlister->get_font_family() ) != 0 ) { // Changed font-family - if( act->active == -1 ) { + if( _font_family_item->get_active() == -1 ) { // New font-family, not in document, not on system (could be fallback list) fontlister->insert_font_family( new_family ); - act->active = 0; // New family is always at top of list. + + // This just sets a variable in the ComboBoxEntryAction object... + // shouldn't we also set the actual active row in the combobox? + _font_family_item->set_active(0); // New family is always at top of list. } - fontlister->set_font_family( act->active ); + fontlister->set_font_family( _font_family_item->get_active() ); // active text set in sp_text_toolbox_selection_changed() SPCSSAttr *css = sp_repr_css_attr_new (); @@ -904,7 +809,7 @@ TextToolbar::fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, gpointer d } // unfreeze - toolbar->_freeze = false; + _freeze = false; #ifdef DEBUG_TEXT std::cout << "sp_text_toolbox_fontfamily_changes: exit" << std::endl; @@ -913,24 +818,29 @@ TextToolbar::fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, gpointer d #endif } -void -TextToolbar::fontsize_value_changed( Ink_ComboBoxEntry_Action *act, gpointer data) +GtkWidget * +TextToolbar::create(SPDesktop *desktop) { - auto toolbar = reinterpret_cast<TextToolbar *>(data); + auto tb = Gtk::manage(new TextToolbar(desktop)); + return GTK_WIDGET(tb->gobj()); +} +void +TextToolbar::fontsize_value_changed() +{ // quit if run by the _changed callbacks - if (toolbar->_freeze) { + if (_freeze) { return; } - toolbar->_freeze = true; + _freeze = true; - gchar *text = ink_comboboxentry_action_get_active_text( act ); + gchar *text = _font_size_item->get_active_text(); gchar *endptr; gdouble size = g_strtod( text, &endptr ); if (endptr == text) { // Conversion failed, non-numeric input. g_warning( "Conversion of size text to double failed, input: %s\n", text ); g_free( text ); - toolbar->_freeze = false; + _freeze = false; return; } g_free( text ); @@ -999,21 +909,19 @@ TextToolbar::fontsize_value_changed( Ink_ComboBoxEntry_Action *act, gpointer dat sp_repr_css_attr_unref (css); - toolbar->_freeze = false; + _freeze = false; } void -TextToolbar::fontstyle_value_changed( Ink_ComboBoxEntry_Action *act, gpointer data) +TextToolbar::fontstyle_value_changed() { - auto toolbar = reinterpret_cast<TextToolbar *>(data); - // quit if run by the _changed callbacks - if (toolbar->_freeze) { + if (_freeze) { return; } - toolbar->_freeze = true; + _freeze = true; - Glib::ustring new_style = ink_comboboxentry_action_get_active_text( act ); + Glib::ustring new_style = _font_style_item->get_active_text(); Inkscape::FontLister* fontlister = Inkscape::FontLister::get_instance(); @@ -1046,26 +954,26 @@ TextToolbar::fontstyle_value_changed( Ink_ComboBoxEntry_Action *act, gpointer da } - toolbar->_freeze = false; + _freeze = false; } // Handles both Superscripts and Subscripts void -TextToolbar::script_changed( InkToggleAction* act, gpointer data) +TextToolbar::script_changed(Gtk::ToggleToolButton *btn) { - auto toolbar = reinterpret_cast<TextToolbar *>(data); // quit if run by the _changed callbacks - if (toolbar->_freeze) { + if (_freeze) { return; } - toolbar->_freeze = true; + + _freeze = true; // Called by Superscript or Subscript button? - const gchar* name = gtk_action_get_name( GTK_ACTION( act ) ); - gint prop = (strcmp(name, "TextSuperscriptAction") == 0) ? 0 : 1; + auto name = btn->get_name(); + gint prop = (strcmp(name.c_str(), "TextSuperscriptAction") == 0) ? 0 : 1; #ifdef DEBUG_TEXT - std::cout << "sp_text_script_changed: " << prop << std::endl; + std::cout << "TextToolbar::script_changed: " << prop << std::endl; #endif // Query baseline @@ -1125,7 +1033,7 @@ TextToolbar::script_changed( InkToggleAction* act, gpointer data) DocumentUndo::maybeDone(SP_ACTIVE_DESKTOP->getDocument(), "ttb:script", SP_VERB_NONE, _("Text: Change superscript or subscript")); } - toolbar->_freeze = false; + _freeze = false; } void @@ -1796,13 +1704,13 @@ TextToolbar::line_spacing_mode_changed(int mode) // Set "Outer Style" toggle to match mode. switch (mode) { case 0: // Adaptive - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(_outer_style_action), false ); + _outer_style_item->set_active(false); prefs->setInt("/tools/text/outer_style", false); break; case 1: // Minimum case 2: // Even - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(_outer_style_action), true ); + _outer_style_item->set_active(true); prefs->setInt("/tools/text/outer_style", true); break; @@ -1811,7 +1719,7 @@ TextToolbar::line_spacing_mode_changed(int mode) } // Outer style toggle set per mode so that line height widget should be enabled. - gtk_action_set_sensitive(GTK_ACTION(_line_height_action), true); + _line_height_item->set_sensitive(true); // Update "climb rate" Unit const *unit = _tracker->getActiveUnit(); @@ -2021,15 +1929,12 @@ TextToolbar::rotation_value_changed() // Unset line height on selection's inner text objects (tspan, etc.). void -TextToolbar::lineheight_unset_changed(InkToggleAction*act, gpointer data) +TextToolbar::lineheight_unset_changed() { - auto toolbar = reinterpret_cast<TextToolbar *>(data); - // quit if run by the _changed callbacks - if (toolbar->_freeze) { + if (_freeze) { return; } - toolbar->_freeze = true; SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_unset_property(css, "line-height"); @@ -2042,20 +1947,19 @@ TextToolbar::lineheight_unset_changed(InkToggleAction*act, gpointer data) DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT, _("Text: Unset line height.")); - toolbar->_freeze = false; + _freeze = false; } // Changes selection to only text outer elements. void -TextToolbar::outer_style_changed( InkToggleAction *act, gpointer data ) +TextToolbar::outer_style_changed() { - auto toolbar = reinterpret_cast<TextToolbar *>(data); - bool outer = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(act) ); + bool outer = _outer_style_item->get_active(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt("/tools/text/outer_style", outer); // Update widgets to reflect new state of Text Outer Style button. - toolbar->selection_changed(nullptr); + selection_changed(nullptr); } /* @@ -2100,9 +2004,9 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele fontlister->selection_update(); // Update font list, but only if widget already created. - if( _font_family_action->combobox != nullptr ) { - ink_comboboxentry_action_set_active_text( _font_family_action, fontlister->get_font_family().c_str(), fontlister->get_font_family_row() ); - ink_comboboxentry_action_set_active_text( _font_style_action, fontlister->get_font_style().c_str() ); + if( _font_family_item->get_combobox() != nullptr ) { + _font_family_item->set_active_text( fontlister->get_font_family().c_str(), fontlister->get_font_family_row() ); + _font_style_item->set_active_text( fontlister->get_font_style().c_str() ); } // Only flowed text can be justified, only normal text can be kerned... @@ -2177,7 +2081,7 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele // To ensure the value of the combobox is properly set on start-up, only mark // the prefs set if the combobox has already been constructed. - if( _font_family_action->combobox != nullptr ) { + if( _font_family_item->get_combobox() != nullptr ) { _text_style_from_prefs = true; } } else { @@ -2199,13 +2103,13 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele // Freeze to ignore callbacks. //g_object_freeze_notify( G_OBJECT( fontSizeAction->combobox ) ); - sp_text_set_sizes(GTK_LIST_STORE(ink_comboboxentry_action_get_model(_font_size_action)), unit); + sp_text_set_sizes(GTK_LIST_STORE(_font_size_item->get_model()), unit); //g_object_thaw_notify( G_OBJECT( fontSizeAction->combobox ) ); - ink_comboboxentry_action_set_active_text( _font_size_action, os.str().c_str() ); + _font_size_item->set_active_text( os.str().c_str() ); Glib::ustring tooltip = Glib::ustring::format(_("Font size"), " (", sp_style_get_css_unit_string(unit), ")"); - ink_comboboxentry_action_set_tooltip ( _font_size_action, tooltip.c_str()); + _font_size_item->set_tooltip (tooltip.c_str()); // Superscript gboolean superscriptSet = @@ -2214,7 +2118,7 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele query.baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && query.baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUPER ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(_superscript_action), superscriptSet ); + _superscript_item->set_active(superscriptSet); // Subscript gboolean subscriptSet = @@ -2223,7 +2127,7 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele query.baseline_shift.type == SP_BASELINE_SHIFT_LITERAL && query.baseline_shift.literal == SP_CSS_BASELINE_SHIFT_SUB ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(_subscript_action), subscriptSet ); + _subscript_item->set_active(subscriptSet); // Alignment @@ -2232,9 +2136,9 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele // Only flowed text can be left and right justified at the same time. // Disable button if we don't have flowed text. - Glib::RefPtr<Gtk::ListStore> store = _align_action->get_store(); + Glib::RefPtr<Gtk::ListStore> store = _align_item->get_store(); Gtk::TreeModel::Row row = *(store->get_iter("3")); // Justify entry - InkSelectOneActionColumns columns; + UI::Widget::ComboToolItemColumns columns; row[columns.col_sensitive] = isFlow; int activeButton = 0; @@ -2247,7 +2151,7 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele if (query.text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE) activeButton = 1; if (query.text_anchor.computed == SP_CSS_TEXT_ANCHOR_END) activeButton = 2; } - _align_action->set_active( activeButton ); + _align_item->set_active( activeButton ); // Line height (spacing) and line height unit double height; @@ -2313,8 +2217,8 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele _lineheight_unit = line_height_unit; // Enable and turn on only if selection includes an object with line height set. - gtk_action_set_sensitive(GTK_ACTION(_line_height_unset_action), query.line_height.set ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(_line_height_unset_action), query.line_height.set ); + _line_height_unset_item->set_sensitive(query.line_height.set); + _line_height_unset_item->set_active(query.line_height.set); // Line spacing mode: requires calculating mode for each <text> element and the <tspan>s within. Inkscape::Selection *selection = desktop->getSelection(); @@ -2368,23 +2272,23 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele // << ", "<< mode[1] // << ", "<< mode[2] // << ", "<< mode[3] << std::endl; - _line_spacing_action->set_active( activeButtonLS ); + _line_spacing_item->set_active( activeButtonLS ); // Enable/disable line height widget based on mode and Outer Style toggle. if ( (activeButtonLS == 0 && outer) || // Adaptive (activeButtonLS == 1 && !outer) || // Minimum (activeButtonLS == 2 && !outer) // Even ) { - gtk_action_set_sensitive (GTK_ACTION(_line_height_action), false); + _line_height_item->set_sensitive(false); } else { - gtk_action_set_sensitive (GTK_ACTION(_line_height_action), true); + _line_height_item->set_sensitive(true); } // In Minimum and Adaptive modes, don't allow unit change (must remain unitless). if (activeButtonLS == 0 || (activeButtonLS == 1 && outer)) { - _line_height_units_action->set_sensitive(false); + _line_height_units_item->set_sensitive(false); } else { - _line_height_units_action->set_sensitive(true); + _line_height_units_item->set_sensitive(true); } // Word spacing @@ -2408,7 +2312,7 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_RL) activeButton2 = 1; if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_LR) activeButton2 = 2; - _writing_mode_action->set_active( activeButton2 ); + _writing_mode_item->set_active( activeButton2 ); // Orientation int activeButton3 = 0; @@ -2416,16 +2320,16 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_UPRIGHT ) activeButton3 = 1; if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS) activeButton3 = 2; - _orientation_action->set_active( activeButton3 ); + _orientation_item->set_active( activeButton3 ); // Disable text orientation for horizontal text... - _orientation_action->set_sensitive( activeButton2 != 0 ); + _orientation_item->set_sensitive( activeButton2 != 0 ); // Direction int activeButton4 = 0; if (query.direction.computed == SP_CSS_DIRECTION_LTR ) activeButton4 = 0; if (query.direction.computed == SP_CSS_DIRECTION_RTL ) activeButton4 = 1; - _direction_action->set_active( activeButton4 ); + _direction_item->set_active( activeButton4 ); } #ifdef DEBUG_TEXT @@ -2483,9 +2387,9 @@ TextToolbar::selection_changed(Inkscape::Selection * /*selection*/, bool subsele { // Set these here as we don't always have kerning/rotating attributes - gtk_action_set_sensitive( GTK_ACTION(_dx_action), !isFlow ); - gtk_action_set_sensitive( GTK_ACTION(_dy_action), !isFlow ); - gtk_action_set_sensitive( GTK_ACTION(_rotation_action), !isFlow ); + _dx_item->set_sensitive(!isFlow); + _dy_item->set_sensitive(!isFlow); + _rotation_item->set_sensitive(!isFlow); } #ifdef DEBUG_TEXT diff --git a/src/ui/toolbar/text-toolbar.h b/src/ui/toolbar/text-toolbar.h index acc6f3268..00632b663 100644 --- a/src/ui/toolbar/text-toolbar.h +++ b/src/ui/toolbar/text-toolbar.h @@ -32,13 +32,12 @@ #include <gtkmm/adjustment.h> -class InkSelectOneAction; class SPDesktop; -typedef struct _EgeAdjustmentAction EgeAdjustmentAction; -typedef struct _GtkActionGroup GtkActionGroup; -typedef struct _Ink_ComboBoxEntry_Action Ink_ComboBoxEntry_Action; -typedef struct _InkToggleAction InkToggleAction; +namespace Gtk { +class ComboBoxText; +class ToggleToolButton; +} namespace Inkscape { class Selection; @@ -49,6 +48,9 @@ class ToolBase; } namespace Widget { +class ComboBoxEntryToolItem; +class ComboToolItem; +class SpinButtonToolItem; class UnitTracker; } @@ -60,26 +62,26 @@ private: UI::Widget::UnitTracker *_tracker; - Ink_ComboBoxEntry_Action *_font_family_action; - Ink_ComboBoxEntry_Action *_font_size_action; - Ink_ComboBoxEntry_Action *_font_style_action; - InkToggleAction *_superscript_action; - InkToggleAction *_subscript_action; - InkToggleAction *_outer_style_action; - InkToggleAction *_line_height_unset_action; - InkSelectOneAction *_align_action; - InkSelectOneAction *_writing_mode_action; - InkSelectOneAction *_orientation_action; - InkSelectOneAction *_direction_action; - InkSelectOneAction *_line_height_units_action; - InkSelectOneAction *_line_spacing_action; - - EgeAdjustmentAction *_line_height_action; - EgeAdjustmentAction *_word_spacing_action; - EgeAdjustmentAction *_letter_spacing_action; - EgeAdjustmentAction *_dx_action; - EgeAdjustmentAction *_dy_action; - EgeAdjustmentAction *_rotation_action; + UI::Widget::ComboBoxEntryToolItem *_font_family_item; + UI::Widget::ComboBoxEntryToolItem *_font_size_item; + UI::Widget::ComboBoxEntryToolItem *_font_style_item; + Gtk::ToggleToolButton *_superscript_item; + Gtk::ToggleToolButton *_subscript_item; + Gtk::ToggleToolButton *_outer_style_item; + Gtk::ToggleToolButton *_line_height_unset_item; + UI::Widget::ComboToolItem *_align_item; + UI::Widget::ComboToolItem *_writing_mode_item; + UI::Widget::ComboToolItem *_orientation_item; + UI::Widget::ComboToolItem *_direction_item; + UI::Widget::ComboToolItem *_line_height_units_item; + UI::Widget::ComboToolItem *_line_spacing_item; + + UI::Widget::SpinButtonToolItem *_line_height_item; + UI::Widget::SpinButtonToolItem *_word_spacing_item; + UI::Widget::SpinButtonToolItem *_letter_spacing_item; + UI::Widget::SpinButtonToolItem *_dx_item; + UI::Widget::SpinButtonToolItem *_dy_item; + UI::Widget::SpinButtonToolItem *_rotation_item; Glib::RefPtr<Gtk::Adjustment> _line_height_adj; Glib::RefPtr<Gtk::Adjustment> _word_spacing_adj; @@ -94,19 +96,12 @@ private: sigc::connection c_selection_modified; sigc::connection c_subselection_changed; - static void fontfamily_value_changed(Ink_ComboBoxEntry_Action *act, - gpointer data); - static void fontsize_value_changed (Ink_ComboBoxEntry_Action *act, - gpointer data); - static void fontstyle_value_changed (Ink_ComboBoxEntry_Action *act, - gpointer data); - static void script_changed (InkToggleAction *act, - gpointer data); - static void lineheight_unset_changed(InkToggleAction *act, - gpointer data); - static void outer_style_changed (InkToggleAction *act, - gpointer data); - + void fontfamily_value_changed(); + void fontsize_value_changed(); + void fontstyle_value_changed(); + void script_changed(Gtk::ToggleToolButton *btn); + void lineheight_unset_changed(); + void outer_style_changed(); void align_mode_changed(int mode); void writing_mode_changed(int mode); void orientation_changed(int mode); @@ -124,12 +119,13 @@ private: void selection_modified(Inkscape::Selection *selection, guint flags); void subselection_changed(gpointer tc); void watch_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolBase* ec); + void set_sizes(int unit); protected: TextToolbar(SPDesktop *desktop); public: - static GtkWidget * prep(SPDesktop *desktop, GtkActionGroup* mainActions); + static GtkWidget * create(SPDesktop *desktop); }; } diff --git a/src/ui/toolbar/tweak-toolbar.cpp b/src/ui/toolbar/tweak-toolbar.cpp index 16c9b6009..dc5352ccf 100644 --- a/src/ui/toolbar/tweak-toolbar.cpp +++ b/src/ui/toolbar/tweak-toolbar.cpp @@ -243,6 +243,12 @@ TweakToolbar::TweakToolbar(SPDesktop *desktop) } } +void +TweakToolbar::set_mode(int mode) +{ + _mode_buttons[mode]->set_active(); +} + GtkWidget * TweakToolbar::create(SPDesktop *desktop) { diff --git a/src/ui/toolbar/tweak-toolbar.h b/src/ui/toolbar/tweak-toolbar.h index 8995c64e2..cd1c7d048 100644 --- a/src/ui/toolbar/tweak-toolbar.h +++ b/src/ui/toolbar/tweak-toolbar.h @@ -79,6 +79,8 @@ protected: public: static GtkWidget * create(SPDesktop *desktop); + + void set_mode(int mode); }; } } diff --git a/src/ui/tools/lpe-tool.cpp b/src/ui/tools/lpe-tool.cpp index 55ec014ab..d1e7e186c 100644 --- a/src/ui/tools/lpe-tool.cpp +++ b/src/ui/tools/lpe-tool.cpp @@ -36,6 +36,7 @@ #include "util/units.h" +#include "ui/toolbar/lpe-toolbar.h" #include "ui/tools/lpe-tool.h" #include "ui/shape-editor.h" @@ -309,7 +310,13 @@ lpetool_context_switch_mode(LpeTool *lc, Inkscape::LivePathEffect::EffectType co int index = lpetool_mode_to_index(type); if (index != -1) { lc->mode = type; - lc->desktop->setToolboxSelectOneValue ("lpetool_mode_action", index); + auto tb = dynamic_cast<UI::Toolbar::LPEToolbar*>(lc->desktop->get_toolbar_by_name("LPEToolToolbar")); + + if(tb) { + tb->set_mode(index); + } else { + std::cerr << "Could not access LPE toolbar" << std::endl; + } } else { g_warning ("Invalid mode selected: %d", type); return; diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index 28990bd2d..5fed9e806 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -62,6 +62,7 @@ #include "svg/svg.h" #include "svg/svg-color.h" +#include "ui/toolbar/spray-toolbar.h" #include "ui/tools/spray-tool.h" #include "ui/dialog/dialog-manager.h" @@ -1210,7 +1211,14 @@ static void sp_spray_update_area(SprayTool *tc) static void sp_spray_switch_mode(SprayTool *tc, gint mode, bool with_shift) { // Select the button mode - SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue("spray_tool_mode", mode); + auto tb = dynamic_cast<UI::Toolbar::SprayToolbar*>(SP_EVENT_CONTEXT(tc)->desktop->get_toolbar_by_name("SprayToolbar")); + + if(tb) { + tb->set_mode(mode); + } else { + std::cerr << "Could not access Spray toolbar" << std::endl; + } + // Need to set explicitly, because the prefs may not have changed by the previous tc->mode = mode; tc->update_cursor(with_shift); diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index b8cf5549c..42e3520a0 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -74,6 +74,8 @@ #include "svg/svg.h" +#include "ui/toolbar/tweak-toolbar.h" + #include "ui/tools/tweak-tool.h" using Inkscape::DocumentUndo; @@ -1121,7 +1123,14 @@ sp_tweak_update_area (TweakTool *tc) static void sp_tweak_switch_mode (TweakTool *tc, gint mode, bool with_shift) { - SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("tweak_tool_mode", mode); + auto tb = dynamic_cast<UI::Toolbar::TweakToolbar*>(SP_EVENT_CONTEXT(tc)->desktop->get_toolbar_by_name("TweakToolbar")); + + if(tb) { + tb->set_mode(mode); + } else { + std::cerr << "Could not access Tweak toolbar" << std::endl; + } + // need to set explicitly, because the prefs may not have changed by the previous tc->mode = mode; tc->update_cursor(with_shift); @@ -1133,7 +1142,15 @@ sp_tweak_switch_mode_temporarily (TweakTool *tc, gint mode, bool with_shift) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // Juggling about so that prefs have the old value but tc->mode and the button show new mode: gint now_mode = prefs->getInt("/tools/tweak/mode", 0); - SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("tweak_tool_mode", mode); + + auto tb = dynamic_cast<UI::Toolbar::TweakToolbar*>(SP_EVENT_CONTEXT(tc)->desktop->get_toolbar_by_name("TweakToolbar")); + + if(tb) { + tb->set_mode(mode); + } else { + std::cerr << "Could not access Tweak toolbar" << std::endl; + } + // button has changed prefs, restore prefs->setInt("/tools/tweak/mode", now_mode); // changing prefs changed tc->mode, restore back :) diff --git a/src/ui/view/edit-widget-interface.h b/src/ui/view/edit-widget-interface.h index 1bbbbc8bd..eb3e33bb5 100644 --- a/src/ui/view/edit-widget-interface.h +++ b/src/ui/view/edit-widget-interface.h @@ -17,7 +17,8 @@ #include <2geom/point.h> namespace Gtk { -class Window; + class Toolbar; + class Window; } namespace Glib { @@ -132,15 +133,14 @@ struct EditWidgetInterface /// Temporarily block signals and update rotation display virtual void updateRotation() = 0; + virtual Gtk::Toolbar* get_toolbar_by_name(const Glib::ustring&) = 0; + /// In auxiliary toolbox, set focus to widget having specific id virtual void setToolboxFocusTo (const gchar *) = 0; /// In auxiliary toolbox, set value of adjustment with specific id virtual void setToolboxAdjustmentValue (const gchar *, double) = 0; - /// In auxiliary toolbox, select one of the "select one" options (usually radio toggles) - virtual void setToolboxSelectOneValue (const gchar *, gint) = 0; - /// In auxiliary toolbox, return true if specific togglebutton is active virtual bool isToolboxButtonActive (gchar const*) = 0; diff --git a/src/ui/widget/combo-box-entry-tool-item.cpp b/src/ui/widget/combo-box-entry-tool-item.cpp new file mode 100644 index 000000000..2c3a37693 --- /dev/null +++ b/src/ui/widget/combo-box-entry-tool-item.cpp @@ -0,0 +1,684 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A subclass of GtkAction that wraps a GtkComboBoxEntry. + * Features: + * Setting GtkEntryBox width in characters. + * Passing a function for formatting cells. + * Displaying a warning if entry text isn't in list. + * Check comma separated values in text against list. (Useful for font-family fallbacks.) + * Setting names for GtkComboBoxEntry and GtkEntry (actionName_combobox, actionName_entry) + * to allow setting resources. + * + * Author(s): + * Tavmjong Bah + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2010 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +/* + * We must provide for both a toolbar item and a menu item. + * As we don't know which widgets are used (or even constructed), + * we must keep track of things like active entry ourselves. + */ + +#include "combo-box-entry-tool-item.h" + +#include <iostream> +#include <cstring> +#include <glibmm/ustring.h> + +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> +#include <gdkmm/display.h> + +#include "ui/icon-names.h" + +static GQuark gDataName = 0; + + //gDataName = g_quark_from_string("ink_comboboxentry-action"); + +namespace Inkscape { +namespace UI { +namespace Widget { + +ComboBoxEntryToolItem::ComboBoxEntryToolItem(Glib::ustring name, + Glib::ustring label, + Glib::ustring tooltip, + GtkTreeModel *model, + gint entry_width, + gint extra_width, + void *cell_data_func, + void *separator_func, + GtkWidget *focusWidget) + : _label(std::move(label)), + _tooltip(std::move(tooltip)), + _model(model), + _entry_width(entry_width), + _extra_width(extra_width), + _cell_data_func(cell_data_func), + _separator_func(separator_func), + _focusWidget(focusWidget), + _active(-1), + _text(strdup("")), + _entry_completion(nullptr), + _indicator(nullptr), + _popup(false), + _info(nullptr), + _info_cb(nullptr), + _info_cb_id(0), + _info_cb_blocked(false), + _warning(nullptr), + _warning_cb(nullptr), + _warning_cb_id(0), + _warning_cb_blocked(false), + _altx_name(nullptr) +{ + set_name(name); + + gchar *action_name = g_strdup( get_name().c_str() ); + gchar *combobox_name = g_strjoin( nullptr, action_name, "_combobox", NULL ); + gchar *entry_name = g_strjoin( nullptr, action_name, "_entry", NULL ); + g_free( action_name ); + + GtkWidget* comboBoxEntry = gtk_combo_box_new_with_model_and_entry (_model); + gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (comboBoxEntry), 0); + + // Name it so we can muck with it using an RC file + gtk_widget_set_name( comboBoxEntry, combobox_name ); + g_free( combobox_name ); + + { + gtk_widget_set_halign(comboBoxEntry, GTK_ALIGN_START); + gtk_widget_set_hexpand(comboBoxEntry, FALSE); + gtk_widget_set_vexpand(comboBoxEntry, FALSE); + add(*Glib::wrap(comboBoxEntry)); + } + + _combobox = GTK_COMBO_BOX (comboBoxEntry); + + //gtk_combo_box_set_active( GTK_COMBO_BOX( comboBoxEntry ), ink_comboboxentry_action->active ); + gtk_combo_box_set_active( GTK_COMBO_BOX( comboBoxEntry ), 0 ); + + g_signal_connect( G_OBJECT(comboBoxEntry), "changed", G_CALLBACK(combo_box_changed_cb), this ); + + // Optionally add separator function... + if( _separator_func != nullptr ) { + gtk_combo_box_set_row_separator_func( _combobox, + GtkTreeViewRowSeparatorFunc (_separator_func), + nullptr, nullptr ); + } + + // FIXME: once gtk3 migration is done this can be removed + // https://bugzilla.gnome.org/show_bug.cgi?id=734915 + gtk_widget_show_all (comboBoxEntry); + + // Optionally add formatting... + if( _cell_data_func != nullptr ) { + GtkCellRenderer *cell = gtk_cell_renderer_text_new(); + gtk_cell_layout_clear( GTK_CELL_LAYOUT( comboBoxEntry ) ); + gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( comboBoxEntry ), cell, true ); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT( comboBoxEntry ), cell, + GtkCellLayoutDataFunc (_cell_data_func), + nullptr, nullptr ); + } + + // Optionally widen the combobox width... which widens the drop-down list in list mode. + if( _extra_width > 0 ) { + GtkRequisition req; + gtk_widget_get_preferred_size(GTK_WIDGET(_combobox), &req, nullptr); + gtk_widget_set_size_request( GTK_WIDGET( _combobox ), + req.width + _extra_width, -1 ); + } + + // Get reference to GtkEntry and fiddle a bit with it. + GtkWidget *child = gtk_bin_get_child( GTK_BIN(comboBoxEntry) ); + + // Name it so we can muck with it using an RC file + gtk_widget_set_name( child, entry_name ); + g_free( entry_name ); + + if( child && GTK_IS_ENTRY( child ) ) { + + _entry = GTK_ENTRY(child); + + // Change width + if( _entry_width > 0 ) { + gtk_entry_set_width_chars (GTK_ENTRY (child), _entry_width ); + } + + // Add pop-up entry completion if required + if( _popup ) { + popup_enable(); + } + + // Add altx_name if required + if( _altx_name ) { + g_object_set_data( G_OBJECT( child ), _altx_name, _entry ); + } + + // Add signal for GtkEntry to check if finished typing. + g_signal_connect( G_OBJECT(child), "activate", G_CALLBACK(entry_activate_cb), this ); + g_signal_connect( G_OBJECT(child), "key-press-event", G_CALLBACK(keypress_cb), this ); + } + + set_tooltip(tooltip.c_str()); + + show_all(); +} + +// Setters/Getters --------------------------------------------------- + +gchar* +ComboBoxEntryToolItem::get_active_text() +{ + gchar* text = g_strdup( _text ); + return text; +} + +/* + * For the font-family list we need to handle two cases: + * Text is in list store: + * In this case we use row number as the font-family list can have duplicate + * entries, one in the document font part and one in the system font part. In + * order that scrolling through the list works properly we must distinguish + * between the two. + * Text is not in the list store (i.e. default font-family is not on system): + * In this case we have a row number of -1, and the text must be set by hand. + */ +gboolean +ComboBoxEntryToolItem::set_active_text(const gchar* text, int row) +{ + if( strcmp( _text, text ) != 0 ) { + g_free( _text ); + _text = g_strdup( text ); + } + + // Get active row or -1 if none + if( row < 0 ) { + row = get_active_row_from_text(this, _text); + } + _active = row; + + // Set active row, check that combobox has been created. + if( _combobox ) { + gtk_combo_box_set_active( GTK_COMBO_BOX( _combobox ), _active ); + } + + // Fiddle with entry + if( _entry ) { + + // Explicitly set text in GtkEntry box (won't be set if text not in list). + gtk_entry_set_text( _entry, text ); + + // Show or hide warning -- this might be better moved to text-toolbox.cpp + if( _info_cb_id != 0 && + !_info_cb_blocked ) { + g_signal_handler_block (G_OBJECT(_entry), + _info_cb_id ); + _info_cb_blocked = true; + } + if( _warning_cb_id != 0 && + !_warning_cb_blocked ) { + g_signal_handler_block (G_OBJECT(_entry), + _warning_cb_id ); + _warning_cb_blocked = true; + } + + bool set = false; + if( _warning != nullptr ) { + Glib::ustring missing = check_comma_separated_text(); + if( !missing.empty() ) { + gtk_entry_set_icon_from_icon_name( _entry, + GTK_ENTRY_ICON_SECONDARY, + INKSCAPE_ICON("dialog-warning") ); + // Can't add tooltip until icon set + Glib::ustring warning = _warning; + warning += ": "; + warning += missing; + gtk_entry_set_icon_tooltip_text( _entry, + GTK_ENTRY_ICON_SECONDARY, + warning.c_str() ); + + if( _warning_cb ) { + + // Add callback if we haven't already + if( _warning_cb_id == 0 ) { + _warning_cb_id = + g_signal_connect( G_OBJECT(_entry), + "icon-press", + G_CALLBACK(_warning_cb), + this); + } + // Unblock signal + if( _warning_cb_blocked ) { + g_signal_handler_unblock (G_OBJECT(_entry), + _warning_cb_id ); + _warning_cb_blocked = false; + } + } + set = true; + } + } + + if( !set && _info != nullptr ) { + gtk_entry_set_icon_from_icon_name( GTK_ENTRY(_entry), + GTK_ENTRY_ICON_SECONDARY, + INKSCAPE_ICON("edit-select-all") ); + gtk_entry_set_icon_tooltip_text( _entry, + GTK_ENTRY_ICON_SECONDARY, + _info ); + + if( _info_cb ) { + // Add callback if we haven't already + if( _info_cb_id == 0 ) { + _info_cb_id = + g_signal_connect( G_OBJECT(_entry), + "icon-press", + G_CALLBACK(_info_cb), + this); + } + // Unblock signal + if( _info_cb_blocked ) { + g_signal_handler_unblock (G_OBJECT(_entry), + _info_cb_id ); + _info_cb_blocked = false; + } + } + set = true; + } + + if( !set ) { + gtk_entry_set_icon_from_icon_name( GTK_ENTRY(_entry), + GTK_ENTRY_ICON_SECONDARY, + nullptr ); + } + } + + // Return if active text in list + gboolean found = ( _active != -1 ); + return found; +} + +void +ComboBoxEntryToolItem::set_entry_width(gint entry_width) +{ + _entry_width = entry_width; + + // Clamp to limits + if(entry_width < -1) entry_width = -1; + if(entry_width > 100) entry_width = 100; + + // Widget may not have been created.... + if( _entry ) { + gtk_entry_set_width_chars( GTK_ENTRY(_entry), entry_width ); + } +} + +void +ComboBoxEntryToolItem::set_extra_width( gint extra_width ) +{ + _extra_width = extra_width; + + // Clamp to limits + if(extra_width < -1) extra_width = -1; + if(extra_width > 500) extra_width = 500; + + // Widget may not have been created.... + if( _combobox ) { + GtkRequisition req; + gtk_widget_get_preferred_size(GTK_WIDGET(_combobox), &req, nullptr); + gtk_widget_set_size_request( GTK_WIDGET( _combobox ), req.width + _extra_width, -1 ); + } +} + +void +ComboBoxEntryToolItem::popup_enable() +{ + _popup = true; + + // Widget may not have been created.... + if( _entry ) { + + // Check we don't already have a GtkEntryCompletion + if( _entry_completion ) return; + + _entry_completion = gtk_entry_completion_new(); + + gtk_entry_set_completion( _entry, _entry_completion ); + gtk_entry_completion_set_model( _entry_completion, _model ); + gtk_entry_completion_set_text_column( _entry_completion, 0 ); + gtk_entry_completion_set_popup_completion( _entry_completion, true ); + gtk_entry_completion_set_inline_completion( _entry_completion, false ); + gtk_entry_completion_set_inline_selection( _entry_completion, true ); + + g_signal_connect (G_OBJECT (_entry_completion), "match-selected", G_CALLBACK (match_selected_cb), this); + } +} + +void +ComboBoxEntryToolItem::popup_disable() +{ + _popup = false; + + if( _entry_completion ) { + gtk_widget_destroy(GTK_WIDGET(_entry_completion)); + _entry_completion = nullptr; + } +} + +void +ComboBoxEntryToolItem::set_tooltip(const gchar* tooltip) +{ + set_tooltip_text(tooltip); + gtk_widget_set_tooltip_text ( GTK_WIDGET(_combobox), tooltip); + + // Widget may not have been created.... + if( _entry ) { + gtk_widget_set_tooltip_text ( GTK_WIDGET(_entry), tooltip); + } +} + +void +ComboBoxEntryToolItem::set_info(const gchar* info) +{ + g_free( _info ); + _info = g_strdup( info ); + + // Widget may not have been created.... + if( _entry ) { + gtk_entry_set_icon_tooltip_text( GTK_ENTRY(_entry), + GTK_ENTRY_ICON_SECONDARY, + _info ); + } +} + +void +ComboBoxEntryToolItem::set_info_cb(gpointer info_cb) +{ + _info_cb = info_cb; +} + +void +ComboBoxEntryToolItem::set_warning(const gchar* warning) +{ + g_free( _warning ); + _warning = g_strdup( warning ); + + // Widget may not have been created.... + if( _entry ) { + gtk_entry_set_icon_tooltip_text( GTK_ENTRY(_entry), + GTK_ENTRY_ICON_SECONDARY, + _warning ); + } +} + +void +ComboBoxEntryToolItem::set_warning_cb(gpointer warning_cb) +{ + _warning_cb = warning_cb; +} + +void +ComboBoxEntryToolItem::set_altx_name(const gchar* altx_name) +{ + g_free(_altx_name); + _altx_name = g_strdup( altx_name ); + + // Widget may not have been created.... + if(_entry) { + g_object_set_data( G_OBJECT(_entry), _altx_name, _entry ); + } +} + +// Internal --------------------------------------------------- + +// Return row of active text or -1 if not found. If exclude is true, +// use 3d colunm if available to exclude row from checking (useful to +// skip rows added for font-families included in doc and not on +// system) +gint +ComboBoxEntryToolItem::get_active_row_from_text(ComboBoxEntryToolItem *action, + const gchar *target_text, + gboolean exclude, + gboolean ignore_case ) +{ + // Check if text in list + gint row = 0; + gboolean found = false; + GtkTreeIter iter; + gboolean valid = gtk_tree_model_get_iter_first( action->_model, &iter ); + while ( valid ) { + + // See if we should exclude a row + gboolean check = true; // If true, font-family is on system. + if( exclude && gtk_tree_model_get_n_columns( action->_model ) > 2 ) { + gtk_tree_model_get( action->_model, &iter, 2, &check, -1 ); + } + + if( check ) { + // Get text from list entry + gchar* text = nullptr; + gtk_tree_model_get( action->_model, &iter, 0, &text, -1 ); // Column 0 + + if( !ignore_case ) { + // Case sensitive compare + if( strcmp( target_text, text ) == 0 ){ + found = true; + break; + } + } else { + // Case insensitive compare + gchar* target_text_casefolded = g_utf8_casefold( target_text, -1 ); + gchar* text_casefolded = g_utf8_casefold( text, -1 ); + gboolean equal = (strcmp( target_text_casefolded, text_casefolded ) == 0 ); + g_free( text_casefolded ); + g_free( target_text_casefolded ); + if( equal ) { + found = true; + break; + } + } + } + + ++row; + valid = gtk_tree_model_iter_next( action->_model, &iter ); + } + + if( !found ) row = -1; + + return row; +} + +// Checks if all comma separated text fragments are in the list and +// returns a ustring with a list of missing fragments. +// This is useful for checking if all fonts in a font-family fallback +// list are available on the system. +// +// This routine could also create a Pango Markup string to show which +// fragments are invalid in the entry box itself. See: +// http://developer.gnome.org/pango/stable/PangoMarkupFormat.html +// However... it appears that while one can retrieve the PangoLayout +// for a GtkEntry box, it is only a copy and changing it has no effect. +// PangoLayout * pl = gtk_entry_get_layout( entry ); +// pango_layout_set_markup( pl, "NEW STRING", -1 ); // DOESN'T WORK +Glib::ustring +ComboBoxEntryToolItem::check_comma_separated_text() +{ + Glib::ustring missing; + + // Parse fallback_list using a comma as deliminator + gchar** tokens = g_strsplit( _text, ",", 0 ); + + gint i = 0; + while( tokens[i] != nullptr ) { + + // Remove any surrounding white space. + g_strstrip( tokens[i] ); + + if( get_active_row_from_text( this, tokens[i], true, true ) == -1 ) { + missing += tokens[i]; + missing += ", "; + } + ++i; + } + g_strfreev( tokens ); + + // Remove extra comma and space from end. + if( missing.size() >= 2 ) { + missing.resize( missing.size()-2 ); + } + return missing; +} + +// Callbacks --------------------------------------------------- + +void +ComboBoxEntryToolItem::combo_box_changed_cb( GtkComboBox* widget, gpointer data ) +{ + // Two things can happen to get here: + // An item is selected in the drop-down menu. + // Text is typed. + // We only react here if an item is selected. + + // Get action + auto action = reinterpret_cast<ComboBoxEntryToolItem *>( data ); + + // Check if item selected: + gint newActive = gtk_combo_box_get_active(widget); + if( newActive >= 0 && newActive != action->_active ) { + + action->_active = newActive; + + GtkTreeIter iter; + if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX( action->_combobox ), &iter ) ) { + + gchar* text = nullptr; + gtk_tree_model_get( action->_model, &iter, 0, &text, -1 ); + gtk_entry_set_text( action->_entry, text ); + + g_free( action->_text ); + action->_text = text; + } + + // Now let the world know + action->_signal_changed.emit(); + } +} + +void +ComboBoxEntryToolItem::entry_activate_cb( GtkEntry *widget, + gpointer data ) +{ + // Get text from entry box.. check if it matches a menu entry. + + // Get action + auto action = reinterpret_cast<ComboBoxEntryToolItem*>( data ); + + // Get text + g_free( action->_text ); + action->_text = g_strdup( gtk_entry_get_text( widget ) ); + + // Get row + action->_active = + get_active_row_from_text( action, action->_text ); + + // Set active row + gtk_combo_box_set_active( GTK_COMBO_BOX( action->_combobox), action->_active ); + + // Now let the world know + action->_signal_changed.emit(); +} + +gboolean +ComboBoxEntryToolItem::match_selected_cb( GtkEntryCompletion* /*widget*/, GtkTreeModel* model, GtkTreeIter* iter, gpointer data ) +{ + // Get action + auto action = reinterpret_cast<ComboBoxEntryToolItem*>(data); + GtkEntry *entry = action->_entry; + + if( entry) { + gchar *family = nullptr; + gtk_tree_model_get(model, iter, 0, &family, -1); + + // Set text in GtkEntry + gtk_entry_set_text (GTK_ENTRY (entry), family ); + + // Set text in GtkAction + g_free( action->_text ); + action->_text = family; + + // Get row + action->_active = + get_active_row_from_text( action, action->_text ); + + // Set active row + gtk_combo_box_set_active( GTK_COMBO_BOX( action->_combobox), action->_active ); + + // Now let the world know + action->_signal_changed.emit(); + + return true; + } + return false; +} + +void +ComboBoxEntryToolItem::defocus() +{ + if ( _focusWidget ) { + gtk_widget_grab_focus( _focusWidget ); + } +} + +gboolean +ComboBoxEntryToolItem::keypress_cb( GtkWidget * /*widget*/, GdkEventKey *event, gpointer data ) +{ + gboolean wasConsumed = FALSE; /* default to report event not consumed */ + guint key = 0; + auto action = reinterpret_cast<ComboBoxEntryToolItem*>(data); + gdk_keymap_translate_keyboard_state( Gdk::Display::get_default()->get_keymap(), + event->hardware_keycode, (GdkModifierType)event->state, + 0, &key, nullptr, nullptr, nullptr ); + + switch ( key ) { + + // TODO Add bindings for Tab/LeftTab + case GDK_KEY_Escape: + { + //gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal ); + action->defocus(); + wasConsumed = TRUE; + } + break; + + case GDK_KEY_Return: + case GDK_KEY_KP_Enter: + { + action->defocus(); + //wasConsumed = TRUE; + } + break; + + + } + + return wasConsumed; +} + +} +} +} + +/* + 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/combo-box-entry-tool-item.h b/src/ui/widget/combo-box-entry-tool-item.h new file mode 100644 index 000000000..70c8e94e7 --- /dev/null +++ b/src/ui/widget/combo-box-entry-tool-item.h @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A subclass of GtkAction that wraps a GtkComboBoxEntry. + * Features: + * Setting GtkEntryBox width in characters. + * Passing a function for formatting cells. + * Displaying a warning if text isn't in list. + * Setting names for GtkComboBoxEntry and GtkEntry (actionName_combobox, actionName_entry) + * to allow setting resources. + * + * Author(s): + * Tavmjong Bah + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2010 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#ifndef SEEN_INK_COMBOBOXENTRY_ACTION +#define SEEN_INK_COMBOBOXENTRY_ACTION + +#include <gtkmm/toolitem.h> + +namespace Inkscape { +namespace UI { +namespace Widget { + +/** + * Creates a Gtk::ToolItem subclass that wraps a Gtk::ComboBox object. + */ +class ComboBoxEntryToolItem : public Gtk::ToolItem { +private: + Glib::ustring _tooltip; + Glib::ustring _label; + GtkTreeModel *_model; ///< Tree Model + GtkComboBox *_combobox; + GtkEntry *_entry; + gint _entry_width;// Width of GtkEntry in characters. + gint _extra_width;// Extra Width of GtkComboBox.. to widen drop-down list in list mode. + gpointer _cell_data_func; // drop-down menu format + gpointer _separator_func; + gboolean _popup; // Do we pop-up an entry-completion dialog? + GtkEntryCompletion *_entry_completion; + GtkWidget *_focusWidget; ///< The widget to return focus to + + GtkWidget *_indicator; + gint _active; // Index of active menu item (-1 if not in list). + gchar *_text; // Text of active menu item or entry box. + gchar *_info; // Text for tooltip info about entry. + gpointer _info_cb; // Callback for clicking info icon. + gint _info_cb_id; + gboolean _info_cb_blocked; + gchar *_warning; // Text for tooltip warning that entry isn't in list. + gpointer _warning_cb; // Callback for clicking warning icon. + gint _warning_cb_id; + gboolean _warning_cb_blocked; + gchar *_altx_name; // Target for Alt-X keyboard shortcut. + + // Signals + sigc::signal<void> _signal_changed; + + void (*changed) (ComboBoxEntryToolItem* action); + void (*activated) (ComboBoxEntryToolItem* action); + + static gint get_active_row_from_text(ComboBoxEntryToolItem *action, + const gchar *target_text, + gboolean exclude = false, + gboolean ignore_case = false); + void defocus(); + + static void combo_box_changed_cb( GtkComboBox* widget, gpointer data ); + static void entry_activate_cb( GtkEntry *widget, + gpointer data ); + static gboolean match_selected_cb( GtkEntryCompletion *widget, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data); + static gboolean keypress_cb( GtkWidget *widget, + GdkEventKey *event, + gpointer data ); + + Glib::ustring check_comma_separated_text(); + +public: + ComboBoxEntryToolItem(const Glib::ustring name, + const Glib::ustring label, + const Glib::ustring tooltip, + GtkTreeModel *model, + gint entry_width = -1, + gint extra_width = -1, + gpointer cell_data_func = nullptr, + gpointer separator_func = nullptr, + GtkWidget* focusWidget = nullptr); + + gchar* get_active_text(); + gboolean set_active_text(const gchar* text, int row=-1); + + void set_entry_width(gint entry_width); + void set_extra_width(gint extra_width); + + void popup_enable(); + void popup_disable(); + + void set_info( const gchar* info ); + void set_info_cb( gpointer info_cb ); + void set_warning( const gchar* warning_cb ); + void set_warning_cb(gpointer warning ); + void set_tooltip( const gchar* tooltip ); + + void set_altx_name( const gchar* altx_name ); + + // Accessor methods + decltype(_model) get_model() const {return _model;} + decltype(_combobox) get_combobox() const {return _combobox;} + decltype(_entry) get_entry() const {return _entry;} + decltype(_entry_width) get_entry_width() const {return _entry_width;} + decltype(_extra_width) get_extra_width() const {return _extra_width;} + decltype(_cell_data_func) get_cell_data_func() const {return _cell_data_func;} + decltype(_separator_func) get_separator_func() const {return _separator_func;} + decltype(_popup) get_popup() const {return _popup;} + decltype(_focusWidget) get_focus_widget() const {return _focusWidget;} + + decltype(_active) get_active() const {return _active;} + + decltype(_signal_changed) signal_changed() {return _signal_changed;} + + // Mutator methods + void set_model (decltype(_model) model) {_model = model;} + void set_combobox (decltype(_combobox) combobox) {_combobox = combobox;} + void set_entry (decltype(_entry) entry) {_entry = entry;} + void set_cell_data_func(decltype(_cell_data_func) cell_data_func) {_cell_data_func = cell_data_func;} + void set_separator_func(decltype(_separator_func) separator_func) {_separator_func = separator_func;} + void set_popup (decltype(_popup) popup) {_popup = popup;} + void set_focus_widget (decltype(_focusWidget) focus_widget) {_focusWidget = focus_widget;} + + // This doesn't seem right... surely we should set the active row in the Combobox too? + void set_active (decltype(_active) active) {_active = active;} +}; + +} +} +} +#endif /* SEEN_INK_COMBOBOXENTRY_ACTION */ + +/* + 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/combo-tool-item.cpp b/src/ui/widget/combo-tool-item.cpp index a6c44f7eb..b8638ba72 100644 --- a/src/ui/widget/combo-tool-item.cpp +++ b/src/ui/widget/combo-tool-item.cpp @@ -34,15 +34,17 @@ ComboToolItem* ComboToolItem::create(const Glib::ustring &group_label, const Glib::ustring &tooltip, const Glib::ustring &stock_id, - Glib::RefPtr<Gtk::ListStore> store ) + Glib::RefPtr<Gtk::ListStore> store, + bool has_entry) { - return new ComboToolItem(group_label, tooltip, stock_id, store); + return new ComboToolItem(group_label, tooltip, stock_id, store, has_entry); } ComboToolItem::ComboToolItem(Glib::ustring group_label, Glib::ustring tooltip, Glib::ustring stock_id, - Glib::RefPtr<Gtk::ListStore> store ) : + Glib::RefPtr<Gtk::ListStore> store, + bool has_entry) : _group_label(std::move( group_label )), _tooltip(std::move( tooltip )), _stock_id(std::move( stock_id )), @@ -63,9 +65,45 @@ ComboToolItem::ComboToolItem(Glib::ustring group_label, } // Create combobox - _combobox = Gtk::manage (new Gtk::ComboBox()); + _combobox = Gtk::manage (new Gtk::ComboBox(has_entry)); _combobox->set_model(_store); + populate_combobox(); + + _combobox->signal_changed().connect( + sigc::mem_fun(*this, &ComboToolItem::on_changed_combobox)); + + box->add (*_combobox); + + show_all(); +} + +void +ComboToolItem::use_label(bool use_label) +{ + _use_label = use_label; + populate_combobox(); +} + +void +ComboToolItem::use_icon(bool use_icon) +{ + _use_icon = use_icon; + populate_combobox(); +} + +void +ComboToolItem::use_pixbuf(bool use_pixbuf) +{ + _use_pixbuf = use_pixbuf; + populate_combobox(); +} + +void +ComboToolItem::populate_combobox() +{ + _combobox->clear(); + ComboToolItemColumns columns; if (_use_icon) { Gtk::CellRendererPixbuf *renderer = new Gtk::CellRendererPixbuf; @@ -89,13 +127,6 @@ ComboToolItem::ComboToolItem(Glib::ustring group_label, } _combobox->set_active (_active); - - _combobox->signal_changed().connect( - sigc::mem_fun(*this, &ComboToolItem::on_changed_combobox)); - - box->add (*_combobox); - - show_all(); } void diff --git a/src/ui/widget/combo-tool-item.h b/src/ui/widget/combo-tool-item.h index 1e4590163..d2ca874f0 100644 --- a/src/ui/widget/combo-tool-item.h +++ b/src/ui/widget/combo-tool-item.h @@ -54,12 +54,13 @@ public: static ComboToolItem* create(const Glib::ustring &label, const Glib::ustring &tooltip, const Glib::ustring &stock_id, - Glib::RefPtr<Gtk::ListStore> store ); + Glib::RefPtr<Gtk::ListStore> store, + bool has_entry = false); - /* Style of action */ - void use_label( bool use_label ) { _use_label = use_label; } - void use_icon( bool use_icon ) { _use_icon = use_icon; } - void use_pixbuf( bool use_pixbuf ) { _use_pixbuf = use_pixbuf; } + /* Style of combobox */ + void use_label( bool use_label ); + void use_icon( bool use_icon ); + void use_pixbuf( bool use_pixbuf ); void use_group_label( bool use_group_label ) { _use_group_label = use_group_label; } gint get_active() { return _active; } @@ -74,6 +75,7 @@ public: protected: bool on_create_menu_proxy() override; + void populate_combobox(); /* Signals */ sigc::signal<void, int> _changed; @@ -108,7 +110,8 @@ private: ComboToolItem(Glib::ustring group_label, Glib::ustring tooltip, Glib::ustring stock_id, - Glib::RefPtr<Gtk::ListStore> store ); + Glib::RefPtr<Gtk::ListStore> store, + bool has_entry = false); }; } } diff --git a/src/ui/widget/ink-select-one-action.cpp b/src/ui/widget/ink-select-one-action.cpp deleted file mode 100644 index 95f38b511..000000000 --- a/src/ui/widget/ink-select-one-action.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Authors: - * Tavmjong Bah <tavmjong@free.fr> - * - * Copyright (C) 2017 Tavmjong Bah - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - - -/** \file - An action (menu/toolbar item) that allows selecting one choice out of many. - - The choices may be displayed as: - - 1. A group of items in a toolbar with labels and/or icons. - 2. As a drop-down menu with a labels and/or icons. -*/ - -#include "ink-select-one-action.h" - -#include <iostream> -#include <utility> -#include <gtkmm/toolitem.h> -#include <gtkmm/menuitem.h> -#include <gtkmm/radioaction.h> -#include <gtkmm/radiomenuitem.h> -#include <gtkmm/combobox.h> -#include <gtkmm/menu.h> -#include <gtkmm/box.h> -#include <gtkmm/label.h> -#include <gtkmm/image.h> - -InkSelectOneAction* InkSelectOneAction::create(const Glib::ustring &name, - const Glib::ustring &group_label, - const Glib::ustring &tooltip, - const Glib::ustring &stock_id, - Glib::RefPtr<Gtk::ListStore> store ) { - - return new InkSelectOneAction(name, group_label, tooltip, stock_id, store); -} - -InkSelectOneAction::InkSelectOneAction (const Glib::ustring &name, - const Glib::ustring &group_label, - const Glib::ustring &tooltip, - const Glib::ustring &stock_id, - Glib::RefPtr<Gtk::ListStore> store ) : - Gtk::Action(name, stock_id, group_label, tooltip), - _name( name ), - _group_label( group_label ), - _tooltip( tooltip ), - _stock_id( stock_id ), - _store (std::move(store)), - _use_radio (true), - _use_label (true), - _use_icon (true), - _use_pixbuf (false), - _icon_size ( Gtk::ICON_SIZE_LARGE_TOOLBAR ), - _combobox (nullptr), - _radioaction (nullptr), - _menuitem (nullptr) -{ -} - -void InkSelectOneAction::set_active (gint active) { - - if (active < 0) { - std::cerr << "InkSelectOneAction::set_active: active < 0: " << active << std::endl; - return; - } - - if (_active != active) { - - _active = active; - - if (_combobox) { - _combobox->set_active (active); - } - - if (_radioaction) { - _radioaction->set_current_value (active); - } - - if (active < _radiomenuitems.size()) { - _radiomenuitems[ active ]->set_active(); - } - } -} - -Glib::ustring InkSelectOneAction::get_active_text () { - Gtk::TreeModel::Row row = _store->children()[_active]; - InkSelectOneActionColumns columns; - Glib::ustring label = row[columns.col_label]; - return label; -} - -Gtk::Widget* InkSelectOneAction::create_menu_item_vfunc() { - - if (_menuitem == nullptr) { - - _menuitem = Gtk::manage (new Gtk::MenuItem); - Gtk::Menu *menu = Gtk::manage (new Gtk::Menu); - - Gtk::RadioButton::Group group; - int index = 0; - auto children = _store->children(); - for (auto row : children) { - InkSelectOneActionColumns columns; - Glib::ustring label = row[columns.col_label ]; - Glib::ustring icon = row[columns.col_icon ]; - Glib::ustring tooltip = row[columns.col_tooltip ]; - bool sensitive = row[columns.col_sensitive ]; - - Gtk::RadioMenuItem* button = Gtk::manage(new Gtk::RadioMenuItem(group)); - button->set_label (label); - button->set_tooltip_text( tooltip ); - button->set_sensitive( sensitive ); - - button->signal_toggled().connect( sigc::bind<0>( - sigc::mem_fun(*this, &InkSelectOneAction::on_toggled_radiomenu), index++) - ); - - menu->add (*button); - - _radiomenuitems.push_back( button ); - } - - if ( _active < _radiomenuitems.size()) { - _radiomenuitems[ _active ]->set_active(); - } - - _menuitem->set_submenu (*menu); - _menuitem->show_all(); - } - - return _menuitem; -} - - -Gtk::Widget* InkSelectOneAction::create_tool_item_vfunc() { - // Either a group of radio actions or a combobox with labels and/or icons. - - Gtk::ToolItem *tool_item = new Gtk::ToolItem; - - Gtk::Box* box = Gtk::manage(new Gtk::Box()); - tool_item->add (*box); - - if (_use_group_label) { - Gtk::Label *group_label = Gtk::manage (new Gtk::Label( _group_label + ": " )); - box->add( *group_label ); - } - - if (_use_radio) { - // Create radio actions (note: these are not radio buttons). - - Gtk::RadioAction::Group group; - int index = 0; - auto children = _store->children(); - for (auto row : children) { - InkSelectOneActionColumns columns; - Glib::ustring label = row[columns.col_label ]; - Glib::ustring icon = row[columns.col_icon ]; - Glib::ustring tooltip = row[columns.col_tooltip ]; - bool sensitive = row[columns.col_sensitive]; - Glib::RefPtr<Gtk::RadioAction> action; - if (_use_icon) { - action = - Gtk::RadioAction::create_with_icon_name (group, "Anonymous", icon, label, tooltip); - } else { - action = - Gtk::RadioAction::create (group, "Anonymous", label, tooltip); - } - action->set_property( "value", index++ ); // To identify uniquely each radioaction. - action->set_sensitive( sensitive ); - - // Save first action for use in setting/getting active value. - if (!_radioaction) { - _radioaction = action; - } - - Gtk::ToolItem* item = action->create_tool_item(); - box->add (*item); - } - - if (_radioaction) { - _radioaction->set_current_value (_active); - } - - _radioaction->signal_changed().connect( sigc::mem_fun(*this, &InkSelectOneAction::on_changed_radioaction)); - - } else { - // Create combobox - - _combobox = Gtk::manage (new Gtk::ComboBox()); - _combobox->set_model(_store); - - InkSelectOneActionColumns columns; - if (_use_icon) { - Gtk::CellRendererPixbuf *renderer = new Gtk::CellRendererPixbuf; - renderer->set_property ("stock_size", Gtk::ICON_SIZE_LARGE_TOOLBAR); - _combobox->pack_start (*renderer, false); - _combobox->add_attribute (*renderer, "icon_name", columns.col_icon ); - } else if (_use_pixbuf) { - Gtk::CellRendererPixbuf *renderer = new Gtk::CellRendererPixbuf; - //renderer->set_property ("stock_size", Gtk::ICON_SIZE_LARGE_TOOLBAR); - _combobox->pack_start (*renderer, false); - _combobox->add_attribute (*renderer, "pixbuf", columns.col_pixbuf ); - } - - if (_use_label) { - _combobox->pack_start(columns.col_label); - } - - std::vector<Gtk::CellRenderer*> cells = _combobox->get_cells(); - for (auto & cell : cells) { - _combobox->add_attribute (*cell, "sensitive", columns.col_sensitive); - } - - _combobox->set_active (_active); - - _combobox->signal_changed().connect( - sigc::mem_fun(*this, &InkSelectOneAction::on_changed_combobox)); - - box->add (*_combobox); - } - - tool_item->show_all(); - - return tool_item; -} - -void InkSelectOneAction::on_changed_combobox() { - - int row = _combobox->get_active_row_number(); - if (row < 0) row = 0; // Happens when Gtk::ListStore reconstructed - set_active( row ); - _changed.emit (_active); - _changed_after.emit (_active); -} - -void InkSelectOneAction::on_changed_radioaction(const Glib::RefPtr<Gtk::RadioAction>& current) { - - set_active( current->get_current_value() ); - _changed.emit (_active); - _changed_after.emit (_active); -} - -void InkSelectOneAction::on_toggled_radiomenu(int n) { - - // toggled emitted twice, first for button toggled off, second for button toggled on. - // We want to react only to the button turned on. - if ( n < _radiomenuitems.size() &&_radiomenuitems[ n ]->get_active()) { - set_active ( n ); - _changed.emit (_active); - _changed_after.emit (_active); - } -} - -/* - 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/ink-select-one-action.h b/src/ui/widget/ink-select-one-action.h deleted file mode 100644 index efe249da8..000000000 --- a/src/ui/widget/ink-select-one-action.h +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#ifndef SEEN_INK_SELECT_ONE_ACTION -#define SEEN_INK_SELECT_ONE_ACTION - -/* - * Authors: - * Tavmjong Bah <tavmjong@free.fr> - * - * Copyright (C) 2017 Tavmjong Bah - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - -/** - An action (menu/toolbar item) that allows selecting one choice out of many. - - The choices may be displayed as: - - 1. A group of items in a toolbar with labels and/or icons. - 2. As a drop-down menu with a labels and/or icons. -*/ - -#include <gtkmm/action.h> -#include <gtkmm/liststore.h> -#include <sigc++/sigc++.h> -#include <vector> - -namespace Gtk { -class ComboBox; -class RadioAction; -class MenuItem; -class RadioMenuItem; -} - -class InkSelectOneActionColumns : public Gtk::TreeModel::ColumnRecord { - -public: - InkSelectOneActionColumns() { - add (col_label); - add (col_icon); - add (col_pixbuf); - add (col_data); // Used to store a pointer - add (col_tooltip); - add (col_sensitive); - } - Gtk::TreeModelColumn<Glib::ustring> col_label; - Gtk::TreeModelColumn<Glib::ustring> col_icon; - Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > col_pixbuf; - Gtk::TreeModelColumn<void *> col_data; - Gtk::TreeModelColumn<Glib::ustring> col_tooltip; - Gtk::TreeModelColumn<bool> col_sensitive; -}; - - -class InkSelectOneAction : public Gtk::Action { - -public: - - static InkSelectOneAction* create(const Glib::ustring &name, - const Glib::ustring &label, - const Glib::ustring &tooltip, - const Glib::ustring &stock_id, - Glib::RefPtr<Gtk::ListStore> store ); - - /* Style of action */ - void use_radio( bool use_radio ) { _use_radio = use_radio; } - void use_label( bool use_label ) { _use_label = use_label; } - void use_icon( bool use_icon ) { _use_icon = use_icon; } - void use_pixbuf( bool use_pixbuf ) { _use_pixbuf = use_pixbuf; } - void use_group_label( bool use_group_label ) { _use_group_label = use_group_label; } - - gint get_active() { return _active; } - Glib::ustring get_active_text(); - void set_active( gint active ); - void set_icon_size( Gtk::BuiltinIconSize size ) { _icon_size = size; } - - Glib::RefPtr<Gtk::ListStore> get_store() { return _store; } - - sigc::signal<void, int> signal_changed() { return _changed; } - sigc::signal<void, int> signal_changed_after() { return _changed_after; } - -protected: - - Gtk::Widget* create_menu_item_vfunc() override; - Gtk::Widget* create_tool_item_vfunc() override; - - /* Signals */ - sigc::signal<void, int> _changed; - sigc::signal<void, int> _changed_after; // Needed for unit tracker which eats _changed. - -private: - - Glib::ustring _name; - Glib::ustring _group_label; - Glib::ustring _tooltip; - Glib::ustring _stock_id; - Glib::RefPtr<Gtk::ListStore> _store; - - gint _active; /* Active menu item/button */ - - /* Style */ - bool _use_radio; // Applies to tool item only - bool _use_label; - bool _use_icon; // Applies to menu item only - bool _use_pixbuf; - bool _use_group_label; // Applies to tool item only - Gtk::BuiltinIconSize _icon_size; - - /* Combobox in tool */ - Gtk::ComboBox* _combobox; - - /* Need to track one action to get active action. */ - Glib::RefPtr<Gtk::RadioAction> _radioaction; - - Gtk::MenuItem* _menuitem; - std::vector<Gtk::RadioMenuItem*> _radiomenuitems; - - /* Internal Callbacks */ - void on_changed_combobox(); - void on_changed_radioaction(const Glib::RefPtr<Gtk::RadioAction>& current); - void on_toggled_radiomenu(int n); - - InkSelectOneAction (const Glib::ustring &name, - const Glib::ustring &group_label, - const Glib::ustring &tooltip, - const Glib::ustring &stock_id, - Glib::RefPtr<Gtk::ListStore> store ); - -}; - - -#endif /* SEEN_INK_SELECT_ONE_ACTION */ - -/* - 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.cpp b/src/ui/widget/spin-button-tool-item.cpp index f8c285344..e190d8dd2 100644 --- a/src/ui/widget/spin-button-tool-item.cpp +++ b/src/ui/widget/spin-button-tool-item.cpp @@ -3,6 +3,7 @@ #include "spin-button-tool-item.h" #include <gtkmm/box.h> +#include <gtkmm/image.h> #include <gtkmm/radiomenuitem.h> #include <gtkmm/toolbar.h> @@ -390,14 +391,28 @@ SpinButtonToolItem::SpinButtonToolItem(const Glib::ustring name, _btn->add_events(Gdk::KEY_PRESS_MASK); // Create a label - auto label = Gtk::manage(new Gtk::Label(label_text)); + _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); + _hbox = Gtk::manage(new Gtk::Box()); + _hbox->set_spacing(3); + _hbox->pack_start(*_label); + _hbox->pack_start(*_btn); + add(*_hbox); + show_all(); +} + +void +SpinButtonToolItem::set_icon(const Glib::ustring& icon_name) +{ + _hbox->remove(*_label); + _icon = Gtk::manage(new Gtk::Image(icon_name, Gtk::ICON_SIZE_SMALL_TOOLBAR)); + + if(_icon) { + _hbox->pack_start(*_icon); + _hbox->reorder_child(*_icon, 0); + } + show_all(); } diff --git a/src/ui/widget/spin-button-tool-item.h b/src/ui/widget/spin-button-tool-item.h index 1b33e8580..4386d4799 100644 --- a/src/ui/widget/spin-button-tool-item.h +++ b/src/ui/widget/spin-button-tool-item.h @@ -5,6 +5,7 @@ #include <gtkmm/toolitem.h> namespace Gtk { +class Box; class RadioButtonGroup; class RadioMenuItem; } @@ -29,6 +30,10 @@ private: double _last_val; ///< The last value of the adjustment bool _transfer_focus; ///< Whether or not to transfer focus + Gtk::Box *_hbox; ///< Horizontal box, to store widgets + Gtk::Widget *_label; ///< A text label to describe the setting + Gtk::Widget *_icon; ///< An icon to describe the setting + /** A widget that grabs focus when this one loses it */ Gtk::Widget * _focus_widget; @@ -72,6 +77,7 @@ public: void set_custom_numeric_menu_data(std::vector<double>& values, const std::vector<Glib::ustring>& labels = std::vector<Glib::ustring>()); Glib::RefPtr<Gtk::Adjustment> get_adjustment(); + void set_icon(const Glib::ustring& icon_name); }; } // namespace Widget } // namespace UI diff --git a/src/ui/widget/unit-tracker.cpp b/src/ui/widget/unit-tracker.cpp index 4abfaa9c8..0bdd3210a 100644 --- a/src/ui/widget/unit-tracker.cpp +++ b/src/ui/widget/unit-tracker.cpp @@ -19,7 +19,6 @@ #include "unit-tracker.h" -#include "ink-select-one-action.h" #include "combo-tool-item.h" #define COLUMN_STRING 0 @@ -41,7 +40,7 @@ UnitTracker::UnitTracker(UnitType unit_type) : { UnitTable::UnitMap m = unit_table.units(unit_type); - InkSelectOneActionColumns columns; + ComboToolItemColumns columns; _store = Gtk::ListStore::create(columns); Gtk::TreeModel::Row row; @@ -67,7 +66,6 @@ UnitTracker::UnitTracker(UnitType unit_type) : UnitTracker::~UnitTracker() { - _actionList.clear(); _combo_list.clear(); // Unhook weak references to GtkAdjustments @@ -91,7 +89,7 @@ void UnitTracker::setActiveUnit(Inkscape::Util::Unit const *unit) { if (unit) { - InkSelectOneActionColumns columns; + ComboToolItemColumns columns; int index = 0; for (auto& row: _store->children() ) { Glib::ustring storedUnit = row[columns.col_label]; @@ -122,7 +120,7 @@ void UnitTracker::addAdjustment(GtkAdjustment *adj) void UnitTracker::addUnit(Inkscape::Util::Unit const *u) { - InkSelectOneActionColumns columns; + ComboToolItemColumns columns; Gtk::TreeModel::Row row; row = *(_store->append()); @@ -134,7 +132,7 @@ void UnitTracker::addUnit(Inkscape::Util::Unit const *u) void UnitTracker::prependUnit(Inkscape::Util::Unit const *u) { - InkSelectOneActionColumns columns; + ComboToolItemColumns columns; Gtk::TreeModel::Row row; row = *(_store->prepend()); @@ -153,28 +151,6 @@ void UnitTracker::setFullVal(GtkAdjustment *adj, gdouble val) _priorValues[adj] = val; } -/** - * \deprecated Use create_tool_item instead - */ -InkSelectOneAction *UnitTracker::createAction(Glib::ustring const &name, - Glib::ustring const &label, - Glib::ustring const &tooltip) -{ - InkSelectOneAction* act = - InkSelectOneAction::create( name, label, tooltip, "NotUsed", _store); - - act->use_radio( false ); - act->use_label( true ); - act->use_icon( false ); - act->use_group_label( false ); - act->set_active( _active ); - - act->signal_changed().connect(sigc::mem_fun(*this, &UnitTracker::_unitChangedCB)); - _actionList.push_back(act); - - return act; -} - ComboToolItem * UnitTracker::create_tool_item(Glib::ustring const &label, Glib::ustring const &tooltip) @@ -192,14 +168,6 @@ void UnitTracker::_unitChangedCB(int active) _setActive(active); } -void UnitTracker::_actionFinalizedCB(gpointer data, GObject *where_the_object_was) -{ - if (data && where_the_object_was) { - UnitTracker *self = reinterpret_cast<UnitTracker *>(data); - self->_actionFinalized(where_the_object_was); - } -} - void UnitTracker::_adjustmentFinalizedCB(gpointer data, GObject *where_the_object_was) { if (data && where_the_object_was) { @@ -208,17 +176,6 @@ void UnitTracker::_adjustmentFinalizedCB(gpointer data, GObject *where_the_objec } } -void UnitTracker::_actionFinalized(GObject *where_the_object_was) -{ - InkSelectOneAction* act = (InkSelectOneAction*)(where_the_object_was); - auto it = std::find(_actionList.begin(),_actionList.end(), act); - if (it != _actionList.end()) { - _actionList.erase(it); - } else { - g_warning("Received a finalization callback for unknown object %p", where_the_object_was); - } -} - void UnitTracker::_adjustmentFinalized(GObject *where_the_object_was) { GtkAdjustment* adj = (GtkAdjustment*)(where_the_object_was); @@ -238,7 +195,7 @@ void UnitTracker::_setActive(gint active) if (_store) { // Find old and new units - InkSelectOneActionColumns columns; + ComboToolItemColumns columns; int index = 0; Glib::ustring oldAbbr( "NotFound" ); Glib::ustring newAbbr( "NotFound" ); @@ -274,10 +231,6 @@ void UnitTracker::_setActive(gint active) } _active = active; - for (auto act: _actionList) { - act->set_active (active); - } - for (auto combo : _combo_list) { if(combo) combo->set_active(active); } diff --git a/src/ui/widget/unit-tracker.h b/src/ui/widget/unit-tracker.h index c876d8224..1f16292ff 100644 --- a/src/ui/widget/unit-tracker.h +++ b/src/ui/widget/unit-tracker.h @@ -20,17 +20,13 @@ #include <vector> #include <gtkmm/liststore.h> -#include <gtkmm/action.h> #include "util/units.h" -class InkSelectOneAction; - using Inkscape::Util::Unit; using Inkscape::Util::UnitType; typedef struct _GObject GObject; -typedef struct _GtkAction GtkAction; typedef struct _GtkAdjustment GtkAdjustment; typedef struct _GtkListStore GtkListStore; @@ -55,10 +51,6 @@ public: void prependUnit(Inkscape::Util::Unit const *u); void setFullVal(GtkAdjustment *adj, gdouble val); - InkSelectOneAction *createAction(Glib::ustring const &name, - Glib::ustring const &label, - Glib::ustring const &tooltip); - ComboToolItem *create_tool_item(Glib::ustring const &label, Glib::ustring const &tooltip); @@ -68,14 +60,12 @@ protected: private: // Callbacks void _unitChangedCB(int active); - static void _actionFinalizedCB(gpointer data, GObject *where_the_object_was); static void _adjustmentFinalizedCB(gpointer data, GObject *where_the_object_was); void _setActive(gint index); void _fixupAdjustments(Inkscape::Util::Unit const *oldUnit, Inkscape::Util::Unit const *newUnit); // Cleanup - void _actionFinalized(GObject *where_the_object_was); void _adjustmentFinalized(GObject *where_the_object_was); gint _active; @@ -84,7 +74,6 @@ private: bool _activeUnitInitialized; Glib::RefPtr<Gtk::ListStore> _store; - std::vector<InkSelectOneAction*> _actionList; std::vector<ComboToolItem *> _combo_list; std::vector<GtkAdjustment*> _adjList; std::map <GtkAdjustment *, gdouble> _priorValues; diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index c6dad3f1a..4c0617167 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -3,14 +3,12 @@ add_subdirectory(gimp) set(widgets_SRC desktop-widget.cpp - ege-adjustment-action.cpp ege-paint-def.cpp fill-style.cpp gradient-image.cpp gradient-selector.cpp gradient-vector.cpp ink-action.cpp - ink-comboboxentry-action.cpp ink-toggle-action.cpp paint-selector.cpp sp-attribute-widget.cpp @@ -26,7 +24,6 @@ set(widgets_SRC # ------- # Headers desktop-widget.h - ege-adjustment-action.h ege-paint-def.h fill-n-stroke-factory.h fill-style.h @@ -34,7 +31,6 @@ set(widgets_SRC gradient-selector.h gradient-vector.h ink-action.h - ink-comboboxentry-action.h ink-toggle-action.h paint-selector.h sp-attribute-widget.h diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index e94448e2c..8bf236972 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -60,7 +60,6 @@ #include "ui/uxmanager.h" #include "ui/widget/button.h" #include "ui/widget/dock.h" -#include "ui/widget/ink-select-one-action.h" #include "ui/widget/layer-selector.h" #include "ui/widget/selected-style.h" #include "ui/widget/spin-button-tool-item.h" @@ -1527,6 +1526,22 @@ void SPDesktopWidget::layoutWidgets() } } +Gtk::Toolbar * +SPDesktopWidget::get_toolbar_by_name(const Glib::ustring& name) +{ + // The name is actually attached to the GtkGrid that contains + // the toolbar, so we need to get the grid first + auto widget = sp_search_by_name_recursive(Glib::wrap(aux_toolbox), name); + auto grid = dynamic_cast<Gtk::Grid*>(widget); + + if (!grid) return nullptr; + + auto child = grid->get_child_at(0,0); + auto tb = dynamic_cast<Gtk::Toolbar*>(child); + + return tb; +} + void SPDesktopWidget::setToolboxFocusTo (const gchar* label) { @@ -1565,15 +1580,6 @@ SPDesktopWidget::setToolboxAdjustmentValue (gchar const *id, double value) else g_warning ("Could not find GtkAdjustment for %s\n", id); } -void -SPDesktopWidget::setToolboxSelectOneValue (gchar const *id, int value) -{ - gpointer hb = sp_search_by_data_recursive(aux_toolbox, (gpointer) id); - if (static_cast<InkSelectOneAction*>(hb)) { - static_cast<InkSelectOneAction*>(hb)->set_active( value ); - } -} - bool SPDesktopWidget::isToolboxButtonActive (const gchar* id) diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index d21ba7bb8..59c031120 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -218,11 +218,10 @@ public: void updateZoom() override { _dtw->update_zoom(); } void letZoomGrabFocus() override { _dtw->letZoomGrabFocus(); } void updateRotation() override { _dtw->update_rotation(); } + Gtk::Toolbar* get_toolbar_by_name(const Glib::ustring& name) override {return _dtw->get_toolbar_by_name(name);} void setToolboxFocusTo(const gchar *id) override { _dtw->setToolboxFocusTo(id); } void setToolboxAdjustmentValue(const gchar *id, double val) override { _dtw->setToolboxAdjustmentValue (id, val); } - void setToolboxSelectOneValue (gchar const *id, int val) override - { _dtw->setToolboxSelectOneValue (id, val); } bool isToolboxButtonActive (gchar const* id) override { return _dtw->isToolboxButtonActive (id); } void setCoordinateStatus (Geom::Point p) override @@ -255,9 +254,9 @@ public: void presentWindow(); bool showInfoDialog( Glib::ustring const &message ); bool warnDialog (Glib::ustring const &text); + Gtk::Toolbar* get_toolbar_by_name(const Glib::ustring& name); void setToolboxFocusTo (gchar const *); void setToolboxAdjustmentValue (gchar const * id, double value); - void setToolboxSelectOneValue (gchar const * id, gint value); bool isToolboxButtonActive (gchar const *id); void setToolboxPosition(Glib::ustring const& id, GtkPositionType pos); void setCoordinateStatus(Geom::Point p); diff --git a/src/widgets/ege-adjustment-action.cpp b/src/widgets/ege-adjustment-action.cpp deleted file mode 100644 index 49280bcd3..000000000 --- a/src/widgets/ege-adjustment-action.cpp +++ /dev/null @@ -1,1130 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later OR MPL-1.1 OR LGPL-2.1-or-later -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is EGE Adjustment Action. - * - * The Initial Developer of the Original Code is - * Jon A. Cruz. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* Note: this file should be kept compilable as both .cpp and .c */ - -#include <cmath> -#include <cstring> -#include <vector> -#include <algorithm> - -#include <gtkmm/container.h> -#include <gtkmm/radiomenuitem.h> -#include <gtkmm/adjustment.h> -#include <gdk/gdkkeysyms.h> -#include <gdkmm/display.h> - -#include "ui/icon-loader.h" -#include "ui/icon-names.h" -#include "ui/widget/ink-spinscale.h" -#include "widgets/ege-adjustment-action.h" - -static void ege_adjustment_action_finalize( GObject* object ); -static void ege_adjustment_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec ); -static void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec ); - -static GtkWidget* create_menu_item( GtkAction* action ); -static GtkWidget* create_tool_item( GtkAction* action ); -static void connect_proxy( GtkAction *action, GtkWidget *proxy ); -static void disconnect_proxy( GtkAction *action, GtkWidget *proxy ); - -static gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data ); -static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data ); -static gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data ); - -static void ege_adjustment_action_defocus( EgeAdjustmentAction* action ); - -static void egeAct_free_description( gpointer data, gpointer user_data ); -static void egeAct_free_all_descriptions( EgeAdjustmentAction* action ); - -static EgeCreateAdjWidgetCB gFactoryCb = nullptr; -static GQuark gDataName = 0; - -enum { - APPEARANCE_UNKNOWN = -1, - APPEARANCE_NONE = 0, - APPEARANCE_FULL, /* label, then all choices represented by separate buttons */ - APPEARANCE_COMPACT, /* label, then choices in a drop-down menu */ - APPEARANCE_MINIMAL, /* no label, just choices in a drop-down menu */ -}; - -/* TODO need to have appropriate icons setup for these: */ -static const gchar *floogles[] = { - INKSCAPE_ICON("list-remove"), - INKSCAPE_ICON("list-add"), - INKSCAPE_ICON("go-down"), - INKSCAPE_ICON("help-about"), - INKSCAPE_ICON("go-up"), - nullptr}; - -typedef struct _EgeAdjustmentDescr EgeAdjustmentDescr; - -struct _EgeAdjustmentDescr -{ - gchar* descr; - gdouble value; -}; - -typedef struct { - GtkAdjustment* adj; - GtkWidget* focusWidget; - gdouble climbRate; - guint digits; - gdouble epsilon; - gchar* format; - gchar* selfId; - EgeWidgetFixup toolPost; - gdouble lastVal; - gdouble step; - gdouble page; - gint appearanceMode; - gboolean transferFocus; - std::vector<EgeAdjustmentDescr*> descriptions; - gchar* appearance; - gchar* iconId; - GtkIconSize iconSize; - Inkscape::UI::Widget::UnitTracker *unitTracker; -} EgeAdjustmentActionPrivate; - -#define EGE_ADJUSTMENT_ACTION_GET_PRIVATE(o) \ - reinterpret_cast<EgeAdjustmentActionPrivate *>( ege_adjustment_action_get_instance_private (o)) - -enum { - PROP_ADJUSTMENT = 1, - PROP_FOCUS_WIDGET, - PROP_CLIMB_RATE, - PROP_DIGITS, - PROP_SELFID, - PROP_TOOL_POST, - PROP_APPEARANCE, - PROP_ICON_ID, - PROP_ICON_SIZE, - PROP_UNIT_TRACKER -}; - -enum { - BUMP_TOP = 0, - BUMP_PAGE_UP, - BUMP_UP, - BUMP_NONE, - BUMP_DOWN, - BUMP_PAGE_DOWN, - BUMP_BOTTOM, - BUMP_CUSTOM = 100 -}; - -G_DEFINE_TYPE_WITH_PRIVATE(EgeAdjustmentAction, ege_adjustment_action, GTK_TYPE_ACTION); - -static void ege_adjustment_action_class_init( EgeAdjustmentActionClass* klass ) -{ - if ( klass ) { - GObjectClass * objClass = G_OBJECT_CLASS( klass ); - - gDataName = g_quark_from_string("ege-adj-action"); - - - objClass->finalize = ege_adjustment_action_finalize; - - objClass->get_property = ege_adjustment_action_get_property; - objClass->set_property = ege_adjustment_action_set_property; - - klass->parent_class.create_menu_item = create_menu_item; - klass->parent_class.create_tool_item = create_tool_item; - klass->parent_class.connect_proxy = connect_proxy; - klass->parent_class.disconnect_proxy = disconnect_proxy; - - g_object_class_install_property( objClass, - PROP_ADJUSTMENT, - g_param_spec_object( "adjustment", - "Adjustment", - "The adjustment to change", - GTK_TYPE_ADJUSTMENT, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_FOCUS_WIDGET, - g_param_spec_pointer( "focus-widget", - "Focus Widget", - "The widget to return focus to", - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_CLIMB_RATE, - g_param_spec_double( "climb-rate", - "Climb Rate", - "The acelleraton rate", - 0.0, G_MAXDOUBLE, 0.0, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_DIGITS, - g_param_spec_uint( "digits", - "Digits", - "The number of digits to show", - 0, 20, 0, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_SELFID, - g_param_spec_string( "self-id", - "Self ID", - "Marker for self pointer", - nullptr, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_TOOL_POST, - g_param_spec_pointer( "tool-post", - "Tool Widget post process", - "Function for final adjustments", - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_APPEARANCE, - g_param_spec_string( "appearance", - "Appearance hint", - "A hint for how to display", - "", - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_ICON_ID, - g_param_spec_string( "iconId", - "Icon ID", - "The id for the icon", - "", - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_ICON_SIZE, - g_param_spec_int( "iconSize", - "Icon Size", - "The size the icon", - (int)GTK_ICON_SIZE_MENU, - (int)GTK_ICON_SIZE_DIALOG, - (int)GTK_ICON_SIZE_SMALL_TOOLBAR, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - g_object_class_install_property( objClass, - PROP_UNIT_TRACKER, - g_param_spec_pointer( "unit_tracker", - "Unit Tracker", - "The widget that keeps track of the unit", - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - } -} - -void ege_adjustment_action_set_compact_tool_factory( EgeCreateAdjWidgetCB factoryCb ) -{ - gFactoryCb = factoryCb; -} - -static void ege_adjustment_action_init( EgeAdjustmentAction* action ) -{ - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE( action ); - priv->adj = nullptr; - priv->focusWidget = nullptr; - priv->climbRate = 0.0; - priv->digits = 2; - priv->epsilon = 0.009; - priv->format = g_strdup_printf("%%0.%df%%s%%s", priv->digits); - priv->selfId = nullptr; - priv->toolPost = nullptr; - priv->lastVal = 0.0; - priv->step = 0.0; - priv->page = 0.0; - priv->appearanceMode = APPEARANCE_NONE; - priv->transferFocus = FALSE; - //priv->descriptions = 0; - priv->appearance = nullptr; - priv->iconId = nullptr; - priv->iconSize = GTK_ICON_SIZE_SMALL_TOOLBAR; - priv->unitTracker = nullptr; -} - -static void ege_adjustment_action_finalize( GObject* object ) -{ - EgeAdjustmentAction* action = nullptr; - g_return_if_fail( object != nullptr ); - g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(object) ); - - action = EGE_ADJUSTMENT_ACTION( object ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - - // g_free(NULL) does nothing - g_free( priv->format ); - g_free( priv->selfId ); - g_free( priv->appearance ); - g_free( priv->iconId ); - - egeAct_free_all_descriptions( action ); - - if ( G_OBJECT_CLASS(ege_adjustment_action_parent_class)->finalize ) { - (*G_OBJECT_CLASS(ege_adjustment_action_parent_class)->finalize)(object); - } -} - -EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment, - const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id, - gdouble climb_rate, - guint digits, - Inkscape::UI::Widget::UnitTracker *unit_tracker ) -{ - GObject* obj = (GObject*)g_object_new( EGE_ADJUSTMENT_ACTION_TYPE, - "name", name, - "label", label, - "tooltip", tooltip, - "stock_id", stock_id, - "adjustment", adjustment, - "climb-rate", climb_rate, - "digits", digits, - "unit_tracker", unit_tracker, - NULL ); - - EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj ); - - return action; -} - -static void ege_adjustment_action_get_property( GObject* obj, guint propId, GValue* value, GParamSpec * pspec ) -{ - EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - switch ( propId ) { - case PROP_ADJUSTMENT: - g_value_set_object( value, priv->adj ); - break; - - case PROP_FOCUS_WIDGET: - g_value_set_pointer( value, priv->focusWidget ); - break; - - case PROP_CLIMB_RATE: - g_value_set_double( value, priv->climbRate ); - break; - - case PROP_DIGITS: - g_value_set_uint( value, priv->digits ); - break; - - case PROP_SELFID: - g_value_set_string( value, priv->selfId ); - break; - - case PROP_TOOL_POST: - g_value_set_pointer( value, (void*)priv->toolPost ); - break; - - case PROP_APPEARANCE: - g_value_set_string( value, priv->appearance ); - break; - - case PROP_ICON_ID: - g_value_set_string( value, priv->iconId ); - break; - - case PROP_ICON_SIZE: - g_value_set_int( value, priv->iconSize ); - break; - - case PROP_UNIT_TRACKER: - g_value_set_pointer( value, priv->unitTracker ); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec ); - } -} - -void ege_adjustment_action_set_property( GObject* obj, guint propId, const GValue *value, GParamSpec* pspec ) -{ - EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( obj ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - switch ( propId ) { - case PROP_ADJUSTMENT: - { - priv->adj = GTK_ADJUSTMENT( g_value_get_object( value ) ); - g_object_get( G_OBJECT(priv->adj), - "step-increment", &priv->step, - "page-increment", &priv->page, - NULL ); - } - break; - - case PROP_FOCUS_WIDGET: - { - /* TODO unhook prior */ - priv->focusWidget = (GtkWidget*)g_value_get_pointer( value ); - } - break; - - case PROP_CLIMB_RATE: - { - /* TODO pass on */ - priv->climbRate = g_value_get_double( value ); - } - break; - - case PROP_DIGITS: - { - /* TODO pass on */ - priv->digits = g_value_get_uint( value ); - switch ( priv->digits ) { - case 0: priv->epsilon = 0.9; break; - case 1: priv->epsilon = 0.09; break; - case 2: priv->epsilon = 0.009; break; - case 3: priv->epsilon = 0.0009; break; - case 4: priv->epsilon = 0.00009; break; - } - if ( priv->format ) { - g_free( priv->format ); - } - priv->format = g_strdup_printf("%%0.%df%%s%%s", priv->digits); - } - break; - - case PROP_SELFID: - { - /* TODO pass on */ - gchar* prior = priv->selfId; - priv->selfId = g_value_dup_string( value ); - g_free( prior ); - } - break; - - case PROP_TOOL_POST: - { - priv->toolPost = (EgeWidgetFixup)g_value_get_pointer( value ); - } - break; - - case PROP_APPEARANCE: - { - gchar* tmp = priv->appearance; - gchar* newVal = g_value_dup_string( value ); - priv->appearance = newVal; - g_free( tmp ); - - if ( !priv->appearance || (strcmp("", newVal) == 0) ) { - priv->appearanceMode = APPEARANCE_NONE; - } else if ( strcmp("full", newVal) == 0 ) { - priv->appearanceMode = APPEARANCE_FULL; - } else if ( strcmp("compact", newVal) == 0 ) { - priv->appearanceMode = APPEARANCE_COMPACT; - } else if ( strcmp("minimal", newVal) == 0 ) { - priv->appearanceMode = APPEARANCE_MINIMAL; - } else { - priv->appearanceMode = APPEARANCE_UNKNOWN; - } - } - break; - - case PROP_ICON_ID: - { - gchar* tmp = priv->iconId; - priv->iconId = g_value_dup_string( value ); - g_free( tmp ); - } - break; - - case PROP_ICON_SIZE: - { - priv->iconSize = (GtkIconSize)g_value_get_int( value ); - } - break; - - case PROP_UNIT_TRACKER: - { - priv->unitTracker = (Inkscape::UI::Widget::UnitTracker*)g_value_get_pointer( value ); - } - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID( obj, propId, pspec ); - } -} - -GtkAdjustment* ege_adjustment_action_get_adjustment( EgeAdjustmentAction* action ) -{ - g_return_val_if_fail( IS_EGE_ADJUSTMENT_ACTION(action), NULL ); - - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - - return priv->adj; -} - -void ege_adjustment_action_set_focuswidget( EgeAdjustmentAction* action, GtkWidget* widget ) -{ - g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(action) ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - - /* TODO unhook prior */ - - priv->focusWidget = widget; -} - -GtkWidget* ege_adjustment_action_get_focuswidget( EgeAdjustmentAction* action ) -{ - g_return_val_if_fail( IS_EGE_ADJUSTMENT_ACTION(action), NULL ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - - return priv->focusWidget; -} - -static void egeAct_free_description( gpointer data, gpointer user_data ) { - (void)user_data; - if ( data ) { - EgeAdjustmentDescr* descr = (EgeAdjustmentDescr*)data; - if ( descr->descr ) { - g_free( descr->descr ); - descr->descr = nullptr; - } - g_free( descr ); - } -} - -static void egeAct_free_all_descriptions( EgeAdjustmentAction* action ) -{ - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - for(auto i:priv->descriptions) { - egeAct_free_description(i,nullptr); - } - for(auto i:priv->descriptions) { - g_free(i); - } - priv->descriptions.clear(); -} - -static gint egeAct_compare_descriptions( gconstpointer a, gconstpointer b ) -{ - gint val = 0; - - EgeAdjustmentDescr const * aa = (EgeAdjustmentDescr const *)a; - EgeAdjustmentDescr const * bb = (EgeAdjustmentDescr const *)b; - - if ( aa && bb ) { - if ( aa->value < bb->value ) { - val = -1; - } else if ( aa->value > bb->value ) { - val = 1; - } - } - - return val; -} - -void ege_adjustment_action_set_descriptions( EgeAdjustmentAction* action, gchar const** descriptions, gdouble const* values, guint count ) -{ - g_return_if_fail( IS_EGE_ADJUSTMENT_ACTION(action) ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - - egeAct_free_all_descriptions( action ); - - if ( count && descriptions && values ) { - guint i = 0; - for ( i = 0; i < count; i++ ) { - EgeAdjustmentDescr* descr = g_new0( EgeAdjustmentDescr, 1 ); - descr->descr = descriptions[i] ? g_strdup( descriptions[i] ) : nullptr; - descr->value = values[i]; - priv->descriptions.push_back(descr); - std::sort(priv->descriptions.begin(),priv->descriptions.end()); - } - } -} - -void ege_adjustment_action_set_appearance( EgeAdjustmentAction* action, gchar const* val ) -{ - g_object_set( G_OBJECT(action), "appearance", val, NULL ); -} - -static void process_menu_action( GtkWidget* obj, gpointer data ) -{ - GtkCheckMenuItem* item = GTK_CHECK_MENU_ITEM(obj); - if ( gtk_check_menu_item_get_active (item)) { - EgeAdjustmentAction* act = (EgeAdjustmentAction*)g_object_get_qdata( G_OBJECT(obj), gDataName ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (act); - gint what = GPOINTER_TO_INT(data); - - - gdouble base = gtk_adjustment_get_value( priv->adj ); - gdouble lower = 0.0; - gdouble upper = 0.0; - gdouble step = 0.0; - gdouble page = 0.0; - g_object_get( G_OBJECT(priv->adj), - "lower", &lower, - "upper", &upper, - "step-increment", &step, - "page-increment", &page, - NULL ); - - switch ( what ) { - case BUMP_TOP: - gtk_adjustment_set_value( priv->adj, upper ); - break; - - case BUMP_PAGE_UP: - gtk_adjustment_set_value( priv->adj, base + page ); - break; - - case BUMP_UP: - gtk_adjustment_set_value( priv->adj, base + step ); - break; - - case BUMP_DOWN: - gtk_adjustment_set_value( priv->adj, base - step ); - break; - - case BUMP_PAGE_DOWN: - gtk_adjustment_set_value( priv->adj, base - page ); - break; - - case BUMP_BOTTOM: - gtk_adjustment_set_value( priv->adj, lower ); - break; - - default: - if ( what >= BUMP_CUSTOM ) { - guint index = what - BUMP_CUSTOM; - if ( index < priv->descriptions.size() ) { - EgeAdjustmentDescr* descr = priv->descriptions[index]; - if ( descr ) { - gtk_adjustment_set_value( priv->adj, descr->value ); - } - } - } - } - } -} - -static void create_single_menu_item( GCallback toggleCb, int val, GtkWidget* menu, EgeAdjustmentAction* act, GtkWidget** dst, Gtk::RadioMenuItem::Group *group, gdouble num, gboolean active ) -{ - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (act); - char* str = nullptr; - EgeAdjustmentDescr* marker = nullptr; - std::vector<EgeAdjustmentDescr*> cur = priv->descriptions; - - for (auto descr:cur) { - gdouble delta = num - descr->value; - if ( delta < 0.0 ) { - delta = -delta; - } - if ( delta < priv->epsilon ) { - marker = descr; - break; - } - } - - str = g_strdup_printf( priv->format, num, - ((marker && marker->descr) ? ": " : ""), - ((marker && marker->descr) ? marker->descr : "")); - - auto rmi = new Gtk::RadioMenuItem(*group,Glib::ustring(str)); - *dst = GTK_WIDGET(rmi->gobj()); - if ( active ) { - gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(*dst), TRUE ); - } - gtk_menu_shell_append( GTK_MENU_SHELL(menu), *dst ); - g_object_set_qdata( G_OBJECT(*dst), gDataName, act ); - - g_signal_connect( G_OBJECT(*dst), "toggled", toggleCb, GINT_TO_POINTER(val) ); - - g_free(str); -} - -static int flush_explicit_items( std::vector<EgeAdjustmentDescr*> descriptions, - int pos, - GCallback toggleCb, - int val, - GtkWidget* menu, - EgeAdjustmentAction* act, - GtkWidget** dst, - Gtk::RadioMenuItem::Group *group, - gdouble num ) -{ - if(pos >= descriptions.size() || pos < 0) return pos; - EgeAdjustmentDescr* descr = descriptions[pos]; - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (act); - - gdouble valUpper = num + priv->epsilon; - gdouble valLower = num - priv->epsilon; - - while ( pos>=0 && pos<descriptions.size() && descr && (descr->value >= valLower) ) { - if ( descr->value > valUpper ) { - create_single_menu_item( toggleCb, val + ( std::find(priv->descriptions.begin(),priv->descriptions.end(),descr) - priv->descriptions.begin() ) , menu, act, dst, group, descr->value, FALSE ); - } - pos--; - descr = (pos<0) ? descriptions[pos] : nullptr; - } - - return pos; -} - -static GtkWidget* create_popup_number_menu( EgeAdjustmentAction* act ) -{ - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (act); - GtkWidget* menu = gtk_menu_new(); - - Gtk::RadioMenuItem::Group group; - GtkWidget* single = nullptr; - std::vector<EgeAdjustmentDescr*> list = priv->descriptions; - int addOns = list.size() - 1; - - gdouble base = gtk_adjustment_get_value( priv->adj ); - gdouble lower = 0.0; - gdouble upper = 0.0; - gdouble step = 0.0; - gdouble page = 0.0; - g_object_get( G_OBJECT(priv->adj), - "lower", &lower, - "upper", &upper, - "step-increment", &step, - "page-increment", &page, - NULL ); - - - if ( base < upper ) { - addOns = flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, upper ); - create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_TOP, menu, act, &single, &group, upper, FALSE ); - if ( (base + page) < upper ) { - addOns = flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base + page ); - create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_PAGE_UP, menu, act, &single, &group, base + page, FALSE ); - } - if ( (base + step) < upper ) { - addOns = flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base + step ); - create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_UP, menu, act, &single, &group, base + step, FALSE ); - } - } - - addOns = flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base ); - create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_NONE, menu, act, &single, &group, base, TRUE ); - - if ( base > lower ) { - if ( (base - step) > lower ) { - addOns = flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base - step ); - create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_DOWN, menu, act, &single, &group, base - step, FALSE ); - } - if ( (base - page) > lower ) { - addOns = flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, base - page ); - create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_PAGE_DOWN, menu, act, &single, &group, base - page, FALSE ); - } - addOns = flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, lower ); - create_single_menu_item( G_CALLBACK(process_menu_action), BUMP_BOTTOM, menu, act, &single, &group, lower, FALSE ); - } - - if ( !priv->descriptions.empty() ) { - gdouble value = ((EgeAdjustmentDescr*)priv->descriptions[0])->value; - flush_explicit_items( list, addOns, G_CALLBACK(process_menu_action), BUMP_CUSTOM, menu, act, &single, &group, value ); - } - - return menu; -} - -static GtkWidget* create_menu_item( GtkAction* action ) -{ - GtkWidget* item = nullptr; - - if ( IS_EGE_ADJUSTMENT_ACTION(action) ) { - EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action ); - GValue value; - GtkWidget* subby = nullptr; - - memset( &value, 0, sizeof(value) ); - g_value_init( &value, G_TYPE_STRING ); - g_object_get_property( G_OBJECT(action), "label", &value ); - - item = gtk_menu_item_new_with_label( g_value_get_string( &value ) ); - - subby = create_popup_number_menu( act ); - gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subby ); - gtk_widget_show_all( subby ); - g_value_unset( &value ); - } else { - item = GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->create_menu_item( action ); - } - - return item; -} - -static void value_changed_cb( GtkSpinButton* spin, EgeAdjustmentAction* act ) -{ - if ( gtk_widget_has_focus( GTK_WIDGET(spin) ) ) { - gint start = 0, end = 0; - if (GTK_IS_EDITABLE(spin) && gtk_editable_get_selection_bounds (GTK_EDITABLE(spin), &start, &end) - && start != end) { - // #167846, #363000 If the spin button has a selection, its probably - // because we got here from a Tab key from another spin, if so don't defocus - return; - } - ege_adjustment_action_defocus( act ); - } -} - -static gboolean event_cb( EgeAdjustmentAction* act, GdkEvent* evt ) -{ - gboolean handled = FALSE; - if ( evt->type == GDK_BUTTON_PRESS ) { - if ( evt->button.button == 3 ) { - if ( IS_EGE_ADJUSTMENT_ACTION(act) ) { - GtkWidget* menu = create_popup_number_menu(act); - gtk_widget_show_all( menu ); - gtk_menu_popup_at_pointer( GTK_MENU(menu), evt ); - } - handled = TRUE; - } - } - - return handled; -} - -static GtkWidget* create_tool_item( GtkAction* action ) -{ - GtkWidget* item = nullptr; - - if ( IS_EGE_ADJUSTMENT_ACTION(action) ) { - EgeAdjustmentAction* act = EGE_ADJUSTMENT_ACTION( action ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (act); - GtkWidget* spinbutton = nullptr; - auto hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); - gtk_box_set_homogeneous(GTK_BOX(hb), FALSE); - GValue value; - memset( &value, 0, sizeof(value) ); - g_value_init( &value, G_TYPE_STRING ); - g_object_get_property( G_OBJECT(action), "short_label", &value ); - - if ( priv->appearanceMode == APPEARANCE_FULL ) { - /* Slider */ - InkSpinScale* inkspinscale = - new InkSpinScale(Glib::wrap(priv->adj)); - inkspinscale->set_label( g_value_get_string( &value )); - inkspinscale->set_digits(0); - spinbutton = (GtkWidget*)inkspinscale->gobj(); - gtk_widget_set_size_request(spinbutton, 100, -1); - - } else if ( priv->appearanceMode == APPEARANCE_MINIMAL ) { - spinbutton = gtk_scale_button_new( GTK_ICON_SIZE_MENU, 0, 100, 2, nullptr ); - gtk_scale_button_set_adjustment( GTK_SCALE_BUTTON(spinbutton), priv->adj ); - gtk_scale_button_set_icons( GTK_SCALE_BUTTON(spinbutton), floogles ); - } else { - if ( gFactoryCb ) { - spinbutton = gFactoryCb( priv->adj, priv->climbRate, priv->digits, priv->unitTracker ); - } else { - spinbutton = gtk_spin_button_new( priv->adj, priv->climbRate, priv->digits ); - } - } - - item = GTK_WIDGET( gtk_tool_item_new() ); - - { - GValue tooltip; - memset( &tooltip, 0, sizeof(tooltip) ); - g_value_init( &tooltip, G_TYPE_STRING ); - g_object_get_property( G_OBJECT(action), "tooltip", &tooltip ); - const gchar* tipstr = g_value_get_string( &tooltip ); - if ( tipstr && *tipstr ) { - gtk_widget_set_tooltip_text( spinbutton, tipstr ); - } - g_value_unset( &tooltip ); - } - - if ( priv->appearanceMode != APPEARANCE_FULL ) { - GtkWidget* filler1 = gtk_label_new(" "); - gtk_box_pack_start( GTK_BOX(hb), filler1, FALSE, FALSE, 0 ); - - /* Use an icon if available or use short-label */ - if ( priv->iconId && strcmp( priv->iconId, "" ) != 0 ) { - GtkWidget *icon = sp_get_icon_image(priv->iconId, priv->iconSize); - gtk_box_pack_start( GTK_BOX(hb), icon, FALSE, FALSE, 0 ); - } else { - GtkWidget* lbl = gtk_label_new( g_value_get_string( &value ) ? g_value_get_string( &value ) : "wwww" ); - gtk_widget_set_halign(lbl, GTK_ALIGN_END); - gtk_box_pack_start( GTK_BOX(hb), lbl, FALSE, FALSE, 0 ); - } - } - - if ( priv->appearanceMode == APPEARANCE_FULL ) { - gtk_box_pack_start( GTK_BOX(hb), spinbutton, TRUE, TRUE, 0 ); - } else { - gtk_box_pack_start( GTK_BOX(hb), spinbutton, FALSE, FALSE, 0 ); - } - - gtk_container_add( GTK_CONTAINER(item), hb ); - - if ( priv->selfId ) { - g_object_set_data( G_OBJECT(spinbutton), priv->selfId, spinbutton ); - } - - g_signal_connect( G_OBJECT(spinbutton), "focus-in-event", G_CALLBACK(focus_in_cb), action ); - g_signal_connect( G_OBJECT(spinbutton), "focus-out-event", G_CALLBACK(focus_out_cb), action ); - g_signal_connect( G_OBJECT(spinbutton), "key-press-event", G_CALLBACK(keypress_cb), action ); - - g_signal_connect( G_OBJECT(spinbutton), "value-changed", G_CALLBACK(value_changed_cb), action ); - - g_signal_connect_swapped( G_OBJECT(spinbutton), "event", G_CALLBACK(event_cb), action ); - if ( priv->appearanceMode == APPEARANCE_FULL ) { - /* */ - } else if ( priv->appearanceMode == APPEARANCE_MINIMAL ) { - /* */ - } else { - gtk_entry_set_width_chars( GTK_ENTRY(spinbutton), priv->digits + 3 ); - } - - gtk_widget_show_all( item ); - - /* Shrink or whatnot after shown */ - if ( priv->toolPost ) { - priv->toolPost( item ); - } - - g_value_unset( &value ); - } else { - item = GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->create_tool_item( action ); - } - - return item; -} - -static void connect_proxy( GtkAction *action, GtkWidget *proxy ) -{ - GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->connect_proxy( action, proxy ); -} - -static void disconnect_proxy( GtkAction *action, GtkWidget *proxy ) -{ - GTK_ACTION_CLASS(ege_adjustment_action_parent_class)->disconnect_proxy( action, proxy ); -} - -void ege_adjustment_action_defocus( EgeAdjustmentAction* action ) -{ - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - if ( priv->transferFocus ) { - if ( priv->focusWidget ) { - gtk_widget_grab_focus( priv->focusWidget ); - } - } -} - -gboolean focus_in_cb( GtkWidget *widget, GdkEventKey *event, gpointer data ) -{ - (void)event; - if ( IS_EGE_ADJUSTMENT_ACTION(data) ) { - EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - if ( GTK_IS_SPIN_BUTTON(widget) ) { - priv->lastVal = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) ); - } else if ( GTK_IS_SCALE_BUTTON(widget) ) { - priv->lastVal = gtk_scale_button_get_value( GTK_SCALE_BUTTON(widget) ); - } else if (GTK_IS_RANGE(widget) ) { - priv->lastVal = gtk_range_get_value( GTK_RANGE(widget) ); - } - priv->transferFocus = TRUE; - } - - return FALSE; /* report event not consumed */ -} - -static gboolean focus_out_cb( GtkWidget *widget, GdkEventKey *event, gpointer data ) -{ - (void)widget; - (void)event; - if ( IS_EGE_ADJUSTMENT_ACTION(data) ) { - EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION( data ); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - priv->transferFocus = FALSE; - } - - return FALSE; /* report event not consumed */ -} - - -static gboolean process_tab( GtkWidget* widget, int direction ) -{ - gboolean handled = FALSE; - GtkWidget* parent = gtk_widget_get_parent(widget); - GtkWidget* gp = parent ? gtk_widget_get_parent(parent) : nullptr; - GtkWidget* ggp = gp ? gtk_widget_get_parent(gp) : nullptr; - - if ( ggp && GTK_IS_TOOLBAR(ggp) ) { - std::vector<Gtk::Widget*> kids = Glib::wrap(GTK_CONTAINER(ggp))->get_children(); - if ( !kids.empty() ) { - GtkWidget* curr = widget; - while ( curr && (gtk_widget_get_parent(curr) != ggp) ) { - curr = gtk_widget_get_parent( curr ); - } - if ( curr ) { - std::vector<Gtk::Widget*>::iterator mid=kids.end(); - for(auto i = kids.begin(); i!= kids.end(); ++i){ - if(curr == (*i)->gobj()) - mid = i; - } - while ( mid != kids.end() && !(mid==kids.begin() && direction<0 ) ) { - mid = ( direction < 0 ) ? std::prev(mid) : ++mid; - if ( mid!=kids.end() && GTK_IS_TOOL_ITEM((*mid)->gobj()) ) { - /* potential target */ - GtkWidget* child = gtk_bin_get_child( GTK_BIN((*mid)->gobj()) ); - if ( child && GTK_IS_BOX(child) ) { /* could be ours */ - std::vector<Gtk::Widget*> subChildren = Glib::wrap(GTK_CONTAINER(child))->get_children(); - if ( ! subChildren.empty() ) { - Gtk::Widget *last = subChildren[subChildren.size()-1]; - if ( GTK_IS_SPIN_BUTTON(last->gobj()) && gtk_widget_is_sensitive( GTK_WIDGET(last->gobj()) ) ) { - gtk_widget_grab_focus( GTK_WIDGET(last->gobj()) ); - handled = TRUE; - mid = kids.end(); /* to stop loop */ - } - } - } - } - } - } - } - } - - return handled; -} - -gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data ) -{ - gboolean wasConsumed = FALSE; /* default to report event not consumed */ - EgeAdjustmentAction* action = EGE_ADJUSTMENT_ACTION(data); - auto priv = EGE_ADJUSTMENT_ACTION_GET_PRIVATE (action); - guint key = 0; - gdk_keymap_translate_keyboard_state( Gdk::Display::get_default()->get_keymap(), - event->hardware_keycode, (GdkModifierType)event->state, - 0, &key, nullptr, nullptr, nullptr ); - - switch ( key ) { - case GDK_KEY_Escape: - { - priv->transferFocus = TRUE; - gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), priv->lastVal ); - ege_adjustment_action_defocus( action ); - wasConsumed = TRUE; - } - break; - - case GDK_KEY_Return: - case GDK_KEY_KP_Enter: - { - priv->transferFocus = TRUE; - ege_adjustment_action_defocus( action ); - wasConsumed = TRUE; - } - break; - - case GDK_KEY_Tab: - { - priv->transferFocus = FALSE; - wasConsumed = process_tab( widget, 1 ); - } - break; - - case GDK_KEY_ISO_Left_Tab: - { - priv->transferFocus = FALSE; - wasConsumed = process_tab( widget, -1 ); - } - break; - - case GDK_KEY_Up: - case GDK_KEY_KP_Up: - { - priv->transferFocus = FALSE; - gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) ); - gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + priv->step ); - wasConsumed = TRUE; - } - break; - - case GDK_KEY_Down: - case GDK_KEY_KP_Down: - { - priv->transferFocus = FALSE; - gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) ); - gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - priv->step ); - wasConsumed = TRUE; - } - break; - - case GDK_KEY_Page_Up: - case GDK_KEY_KP_Page_Up: - { - priv->transferFocus = FALSE; - gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) ); - gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val + priv->page ); - wasConsumed = TRUE; - } - break; - - case GDK_KEY_Page_Down: - case GDK_KEY_KP_Page_Down: - { - priv->transferFocus = FALSE; - gdouble val = gtk_spin_button_get_value( GTK_SPIN_BUTTON(widget) ); - gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), val - priv->page ); - wasConsumed = TRUE; - } - break; - - case GDK_KEY_z: - case GDK_KEY_Z: - { - priv->transferFocus = FALSE; - gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), priv->lastVal ); - wasConsumed = TRUE; - } - break; - - } - - return wasConsumed; -} -/* - 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/ege-adjustment-action.h b/src/widgets/ege-adjustment-action.h deleted file mode 100644 index 14229490c..000000000 --- a/src/widgets/ege-adjustment-action.h +++ /dev/null @@ -1,189 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later OR MPL-1.1 OR LGPL-2.1-or-later -#ifndef SEEN_EGE_ADJUSTMENT_ACTION -#define SEEN_EGE_ADJUSTMENT_ACTION -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is EGE Adjustment Action. - * - * The Initial Developer of the Original Code is - * Jon A. Cruz. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** \file - * GtkAction subclass that represents a GtkAdjustment value. - */ - -/* Note: this file should be kept compilable as both .cpp and .c */ - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - - -#define EGE_ADJUSTMENT_ACTION_TYPE ( ege_adjustment_action_get_type() ) -#define EGE_ADJUSTMENT_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_CAST( (obj), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentAction) ) -#define EGE_ADJUSTMENT_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_CAST( (klass), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionClass) ) -#define IS_EGE_ADJUSTMENT_ACTION( obj ) ( G_TYPE_CHECK_INSTANCE_TYPE( (obj), EGE_ADJUSTMENT_ACTION_TYPE) ) -#define IS_EGE_ADJUSTMENT_ACTION_CLASS( klass ) ( G_TYPE_CHECK_CLASS_TYPE( (klass), EGE_ADJUSTMENT_ACTION_TYPE) ) -#define EGE_ADJUSTMENT_ACTION_GET_CLASS( obj ) ( G_TYPE_INSTANCE_GET_CLASS( (obj), EGE_ADJUSTMENT_ACTION_TYPE, EgeAdjustmentActionClass) ) - -typedef struct _EgeAdjustmentAction EgeAdjustmentAction; -typedef struct _EgeAdjustmentActionClass EgeAdjustmentActionClass; - -namespace Inkscape { - namespace UI { - namespace Widget { - class UnitTracker; - } - } -} - -/** - * Instance structure of EgeAdjustmentAction. - */ -struct _EgeAdjustmentAction -{ - /** Parent instance structure. */ - GtkAction action; -}; - -/** - * Class structure of EgeAdjustmentAction. - */ -struct _EgeAdjustmentActionClass -{ - /** Parent class structure. */ - GtkActionClass parent_class; -}; - -/** Standard Gtk type function */ -GType ege_adjustment_action_get_type( void ); - - -/* - * Note: This normally could be implemented via a GType property for the class to construct, - * but gtkmm classes implemented in C++ only will often not function properly. - * - */ - -/** Callback type for widgets creation factory */ -typedef GtkWidget* (*EgeCreateAdjWidgetCB)( GtkAdjustment *adjustment, gdouble climb_rate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker ); - -/** - * Sets a factory callback to be used to create the specific widget. - * - * @param factoryCb the callback to use to create custom widgets, NULL to use the default. - */ -void ege_adjustment_action_set_compact_tool_factory( EgeCreateAdjWidgetCB factoryCb ); - - -/** - * Creates a new EgeAdjustmentAction instance. - * This is a GtkAction subclass that manages a value stored in a - * GtkAdjustment. - * - * @param adjustment The GtkAdjustment to manage. - * @param name Functional name for the action. - * @param label Display label for the action. - * @param tooltip Tooltip for the action. - * @param stock_id Icon id to use. - * @param climb_rate Used for created widgets. - * @param digits Used for created widgets. - * @param unit_tracker Used to store unit. - */ -EgeAdjustmentAction* ege_adjustment_action_new( GtkAdjustment* adjustment, - const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id, - gdouble climb_rate, - guint digits, - Inkscape::UI::Widget::UnitTracker *unit_tracker - ); -/** - * Returns a pointer to the GtkAdjustment represented by the given - * EgeAdjustmentAction. - * - * @param action The action to fetch the GtkAdjustment for. - */ -GtkAdjustment* ege_adjustment_action_get_adjustment( EgeAdjustmentAction* action ); - -/** - * Sets the GtkWidget to return focus to. - * This is used to be able to transfer focus back out of a toolbar. - * - * @param action The action to set the widget for. - * @param widget The widget to return focus to after editing. - * @see ege_adjustment_action_get_focuswidget - */ -void ege_adjustment_action_set_focuswidget( EgeAdjustmentAction* action, GtkWidget* widget ); - -/** - * Returns a pointer to the GtkWidget to return focus to after changing - * the value. - * - * @param action The action to fetch the focus widget for. - * @returns A pointer to the widget to return focus to, NULL if none set. - * @see ege_adjustment_action_set_focuswidget - */ -GtkWidget* ege_adjustment_action_get_focuswidget( EgeAdjustmentAction* action ); - -/** - * Set a list of values with labels to explicitly include in menus. - * - * @param action The action to set explicit entries for. - * @param descriptions Array of descriptions to include. - * Descriptions will be matched one-for-one with numbers in the 'values' array. - * @param values Array of values to include. - * Values will be matched one-for-one with numbers in the 'descriptions' array. - * @param count Number of items in the 'descriptions' and 'values' arrays. - */ -void ege_adjustment_action_set_descriptions( EgeAdjustmentAction* action, gchar const** descriptions, gdouble const* values, guint count ); - -/** - * Sets a hint to be used in determining the display form. - * This is the XForms style 'appearance' hint: "full", "compact", "minimal". - * - * @param action The action to set the tooltip column for. - * @param val The value of the appearance hint. - */ -void ege_adjustment_action_set_appearance( EgeAdjustmentAction* action, gchar const* val ); - -/** Callback type for post-creation 'fixup' pass on generated widgets */ -typedef void (*EgeWidgetFixup)(GtkWidget *widget); - - -G_END_DECLS - -#endif /* SEEN_EGE_ADJUSTMENT_ACTION */ diff --git a/src/widgets/ink-comboboxentry-action.cpp b/src/widgets/ink-comboboxentry-action.cpp deleted file mode 100644 index a49d5c2c3..000000000 --- a/src/widgets/ink-comboboxentry-action.cpp +++ /dev/null @@ -1,964 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * A subclass of GtkAction that wraps a GtkComboBoxEntry. - * Features: - * Setting GtkEntryBox width in characters. - * Passing a function for formatting cells. - * Displaying a warning if entry text isn't in list. - * Check comma separated values in text against list. (Useful for font-family fallbacks.) - * Setting names for GtkComboBoxEntry and GtkEntry (actionName_combobox, actionName_entry) - * to allow setting resources. - * - * Author(s): - * Tavmjong Bah - * Jon A. Cruz <jon@joncruz.org> - * - * Copyright (C) 2010 Authors - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - -/* - * We must provide for both a toolbar item and a menu item. - * As we don't know which widgets are used (or even constructed), - * we must keep track of things like active entry ourselves. - */ - -#include <iostream> -#include <cstring> -#include <glibmm/ustring.h> - -#include <gtk/gtk.h> -#include <gdk/gdkkeysyms.h> -#include <gdkmm/display.h> - -#include "widgets/ink-comboboxentry-action.h" -#include "ui/icon-names.h" - -// Must handle both tool and menu items! -static GtkWidget* create_tool_item( GtkAction* action ); -static GtkWidget* create_menu_item( GtkAction* action ); - -// Internal -static gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, gboolean exclude = false, gboolean ignore_case = false ); -static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* action ); - -// Callbacks -static void combo_box_changed_cb( GtkComboBox* widget, gpointer data ); -static void entry_activate_cb( GtkEntry* widget, gpointer data ); -static gboolean match_selected_cb( GtkEntryCompletion* widget, GtkTreeModel* model, GtkTreeIter* iter, gpointer data ); -static gboolean keypress_cb( GtkWidget *widget, GdkEventKey *event, gpointer data ); - -enum { - PROP_MODEL = 1, - PROP_COMBOBOX, - PROP_ENTRY, - PROP_ENTRY_WIDTH, - PROP_EXTRA_WIDTH, - PROP_CELL_DATA_FUNC, - PROP_SEPARATOR_FUNC, - PROP_POPUP, - PROP_FOCUS_WIDGET -}; - -enum { - CHANGED = 0, - ACTIVATED, - N_SIGNALS -}; -static guint signals[N_SIGNALS] = {0}; - -static GQuark gDataName = 0; - -static void ink_comboboxentry_action_init (Ink_ComboBoxEntry_Action *action); -static void ink_comboboxentry_action_class_init (Ink_ComboBoxEntry_ActionClass *klass); - -G_DEFINE_TYPE(Ink_ComboBoxEntry_Action, ink_comboboxentry_action, GTK_TYPE_ACTION); - -static void ink_comboboxentry_action_finalize (GObject *object) -{ - // Free any allocated resources. - - G_OBJECT_CLASS (ink_comboboxentry_action_parent_class)->finalize (object); -} - - -static void ink_comboboxentry_action_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) -{ - Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION (object); - - switch(property_id) { - - case PROP_MODEL: - action->model = GTK_TREE_MODEL( g_value_get_object( value )); - break; - - case PROP_COMBOBOX: - action->combobox = GTK_COMBO_BOX (g_value_get_object (value)); - break; - - case PROP_ENTRY: - action->entry = GTK_ENTRY( g_value_get_object( value )); - break; - - case PROP_ENTRY_WIDTH: - action->entry_width = g_value_get_int( value ); - break; - - case PROP_EXTRA_WIDTH: - action->extra_width = g_value_get_int( value ); - break; - - case PROP_CELL_DATA_FUNC: - action->cell_data_func = g_value_get_pointer( value ); - break; - - case PROP_SEPARATOR_FUNC: - action->separator_func = g_value_get_pointer( value ); - break; - - case PROP_POPUP: - action->popup = g_value_get_boolean( value ); - break; - - case PROP_FOCUS_WIDGET: - action->focusWidget = (GtkWidget*)g_value_get_pointer( value ); - break; - - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - - -static void ink_comboboxentry_action_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) -{ - Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION (object); - - switch(property_id) { - - case PROP_MODEL: - g_value_set_object (value, action->model); - break; - - case PROP_COMBOBOX: - g_value_set_object (value, action->combobox); - break; - - case PROP_ENTRY: - g_value_set_object (value, action->entry); - break; - - case PROP_ENTRY_WIDTH: - g_value_set_int (value, action->entry_width); - break; - - case PROP_EXTRA_WIDTH: - g_value_set_int (value, action->extra_width); - break; - - case PROP_CELL_DATA_FUNC: - g_value_set_pointer (value, action->cell_data_func); - break; - - case PROP_SEPARATOR_FUNC: - g_value_set_pointer (value, action->separator_func); - break; - - case PROP_POPUP: - g_value_set_boolean (value, action->popup); - break; - - case PROP_FOCUS_WIDGET: - g_value_set_pointer (value, action->focusWidget); - break; - - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -ink_comboboxentry_action_connect_proxy (GtkAction *action, - GtkWidget *proxy) -{ - /* Override any proxy properties. */ - // if (GTK_IS_MENU_ITEM (proxy)) { - // } - - GTK_ACTION_CLASS (ink_comboboxentry_action_parent_class)->connect_proxy (action, proxy); -} - -static void -ink_comboboxentry_action_class_init (Ink_ComboBoxEntry_ActionClass *klass) -{ - - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkActionClass *gtkaction_class = GTK_ACTION_CLASS (klass); - - gtkaction_class->connect_proxy = ink_comboboxentry_action_connect_proxy; - - gobject_class->finalize = ink_comboboxentry_action_finalize; - gobject_class->set_property = ink_comboboxentry_action_set_property; - gobject_class->get_property = ink_comboboxentry_action_get_property; - - gDataName = g_quark_from_string("ink_comboboxentry-action"); - - klass->parent_class.create_tool_item = create_tool_item; - klass->parent_class.create_menu_item = create_menu_item; - - g_object_class_install_property ( - gobject_class, - PROP_MODEL, - g_param_spec_object ("model", - "Tree Model", - "Tree Model", - GTK_TYPE_TREE_MODEL, - (GParamFlags)G_PARAM_READWRITE)); - g_object_class_install_property ( - gobject_class, - PROP_COMBOBOX, - g_param_spec_object ("combobox", - "GtkComboBoxEntry", - "GtkComboBoxEntry", - GTK_TYPE_WIDGET, - (GParamFlags)G_PARAM_READABLE)); - g_object_class_install_property ( - gobject_class, - PROP_ENTRY, - g_param_spec_object ("entry", - "GtkEntry", - "GtkEntry", - GTK_TYPE_WIDGET, - (GParamFlags)G_PARAM_READABLE)); - g_object_class_install_property ( - gobject_class, - PROP_ENTRY_WIDTH, - g_param_spec_int ("entry_width", - "EntryBox width", - "EntryBox width (characters)", - -1.0, 100, -1.0, - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property ( - gobject_class, - PROP_EXTRA_WIDTH, - g_param_spec_int ("extra_width", - "Extra width", - "Extra width (px)", - -1.0, 500, -1.0, - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property ( - gobject_class, - PROP_CELL_DATA_FUNC, - g_param_spec_pointer ("cell_data_func", - "Cell Data Func", - "Cell Deta Function", - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property ( - gobject_class, - PROP_SEPARATOR_FUNC, - g_param_spec_pointer ("separator_func", - "Separator Func", - "Separator Function", - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property ( - gobject_class, - PROP_POPUP, - g_param_spec_boolean ("popup", - "Entry Popup", - "Entry Popup", - false, - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property( gobject_class, - PROP_FOCUS_WIDGET, - g_param_spec_pointer( "focus-widget", - "Focus Widget", - "The widget to return focus to", - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT) ) ); - - // We need to know when GtkComboBoxEvent or Menu ready for reading - signals[CHANGED] = g_signal_new( "changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(Ink_ComboBoxEntry_ActionClass, changed), - nullptr, nullptr, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - // Probably not needed... originally to keep track of key-presses. - signals[ACTIVATED] = g_signal_new( "activated", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET(Ink_ComboBoxEntry_ActionClass, activated), - nullptr, nullptr, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - -} - -static void ink_comboboxentry_action_init (Ink_ComboBoxEntry_Action *action) -{ - action->active = -1; - action->text = strdup(""); - action->entry_completion = nullptr; - action->indicator = nullptr; - action->popup = false; - action->info = nullptr; - action->info_cb = nullptr; - action->info_cb_id = 0; - action->info_cb_blocked = false; - action->warning = nullptr; - action->warning_cb = nullptr; - action->warning_cb_id = 0; - action->warning_cb_blocked = false; - action->altx_name = nullptr; - action->focusWidget = nullptr; -} - -Ink_ComboBoxEntry_Action *ink_comboboxentry_action_new (const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id, - GtkTreeModel *model, - gint entry_width, - gint extra_width, - void *cell_data_func, - void *separator_func, - GtkWidget *focusWidget) -{ - g_return_val_if_fail (name != nullptr, NULL); - - return (Ink_ComboBoxEntry_Action*)g_object_new (INK_COMBOBOXENTRY_TYPE_ACTION, - "name", name, - "label", label, - "tooltip", tooltip, - "stock-id", stock_id, - "model", model, - "entry_width", entry_width, - "extra_width", extra_width, - "cell_data_func", cell_data_func, - "separator_func", separator_func, - "focus-widget", focusWidget, - NULL); -} - -// Create a widget for a toolbar. -GtkWidget* create_tool_item( GtkAction* action ) -{ - GtkWidget* item = nullptr; - - if ( INK_COMBOBOXENTRY_IS_ACTION( action ) && INK_COMBOBOXENTRY_ACTION(action)->model ) { - - Ink_ComboBoxEntry_Action* ink_comboboxentry_action = INK_COMBOBOXENTRY_ACTION( action ); - - gchar *action_name = g_strdup( gtk_action_get_name( action ) ); - gchar *combobox_name = g_strjoin( nullptr, action_name, "_combobox", NULL ); - gchar *entry_name = g_strjoin( nullptr, action_name, "_entry", NULL ); - g_free( action_name ); - - item = GTK_WIDGET( gtk_tool_item_new() ); - - GtkWidget* comboBoxEntry = gtk_combo_box_new_with_model_and_entry (ink_comboboxentry_action->model); - gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (comboBoxEntry), 0); - - // Name it so we can muck with it using an RC file - gtk_widget_set_name( comboBoxEntry, combobox_name ); - g_free( combobox_name ); - - { - gtk_widget_set_halign(comboBoxEntry, GTK_ALIGN_START); - gtk_widget_set_hexpand(comboBoxEntry, FALSE); - gtk_widget_set_vexpand(comboBoxEntry, FALSE); - gtk_container_add(GTK_CONTAINER(item), comboBoxEntry); - } - - ink_comboboxentry_action->combobox = GTK_COMBO_BOX (comboBoxEntry); - - //gtk_combo_box_set_active( GTK_COMBO_BOX( comboBoxEntry ), ink_comboboxentry_action->active ); - gtk_combo_box_set_active( GTK_COMBO_BOX( comboBoxEntry ), 0 ); - - g_signal_connect( G_OBJECT(comboBoxEntry), "changed", G_CALLBACK(combo_box_changed_cb), action ); - - // Optionally add separator function... - if( ink_comboboxentry_action->separator_func != nullptr ) { - gtk_combo_box_set_row_separator_func( ink_comboboxentry_action->combobox, - GtkTreeViewRowSeparatorFunc (ink_comboboxentry_action->separator_func), - nullptr, nullptr ); - } - - // FIXME: once gtk3 migration is done this can be removed - // https://bugzilla.gnome.org/show_bug.cgi?id=734915 - gtk_widget_show_all (comboBoxEntry); - - // Optionally add formatting... - if( ink_comboboxentry_action->cell_data_func != nullptr ) { - GtkCellRenderer *cell = gtk_cell_renderer_text_new(); - gtk_cell_layout_clear( GTK_CELL_LAYOUT( comboBoxEntry ) ); - gtk_cell_layout_pack_start( GTK_CELL_LAYOUT( comboBoxEntry ), cell, true ); - gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT( comboBoxEntry ), cell, - GtkCellLayoutDataFunc (ink_comboboxentry_action->cell_data_func), - nullptr, nullptr ); - } - - // Optionally widen the combobox width... which widens the drop-down list in list mode. - if( ink_comboboxentry_action->extra_width > 0 ) { - GtkRequisition req; - gtk_widget_get_preferred_size(GTK_WIDGET(ink_comboboxentry_action->combobox), &req, nullptr); - gtk_widget_set_size_request( GTK_WIDGET( ink_comboboxentry_action->combobox ), - req.width + ink_comboboxentry_action->extra_width, -1 ); - } - - // Get reference to GtkEntry and fiddle a bit with it. - GtkWidget *child = gtk_bin_get_child( GTK_BIN(comboBoxEntry) ); - - // Name it so we can muck with it using an RC file - gtk_widget_set_name( child, entry_name ); - g_free( entry_name ); - - if( child && GTK_IS_ENTRY( child ) ) { - - ink_comboboxentry_action->entry = GTK_ENTRY(child); - - // Change width - if( ink_comboboxentry_action->entry_width > 0 ) { - gtk_entry_set_width_chars (GTK_ENTRY (child), ink_comboboxentry_action->entry_width ); - } - - // Add pop-up entry completion if required - if( ink_comboboxentry_action->popup ) { - ink_comboboxentry_action_popup_enable( ink_comboboxentry_action ); - } - - // Add altx_name if required - if( ink_comboboxentry_action->altx_name ) { - g_object_set_data( G_OBJECT( child ), ink_comboboxentry_action->altx_name, ink_comboboxentry_action->entry ); - } - - // Add signal for GtkEntry to check if finished typing. - g_signal_connect( G_OBJECT(child), "activate", G_CALLBACK(entry_activate_cb), action ); - g_signal_connect( G_OBJECT(child), "key-press-event", G_CALLBACK(keypress_cb), action ); - } - - gtk_activatable_set_related_action( GTK_ACTIVATABLE (item), GTK_ACTION( action ) ); - gtk_widget_show_all( item ); - - } else { - - item = GTK_ACTION_CLASS(ink_comboboxentry_action_parent_class)->create_tool_item( action ); - - } - - return item; -} - -// Create a drop-down menu. -GtkWidget* create_menu_item( GtkAction* action ) -{ - GtkWidget* item = nullptr; - - item = GTK_ACTION_CLASS(ink_comboboxentry_action_parent_class)->create_menu_item( action ); - g_warning( "ink_comboboxentry_action: create_menu_item not implemented" ); - // One can easily modify ege-select-one-action routine to implement this. - return item; -} - -// Setters/Getters --------------------------------------------------- - -GtkTreeModel *ink_comboboxentry_action_get_model( Ink_ComboBoxEntry_Action* action ) { - - return action->model; -} - -GtkComboBox *ink_comboboxentry_action_get_comboboxentry( Ink_ComboBoxEntry_Action* action ) { - - return action->combobox; -} - -gchar* ink_comboboxentry_action_get_active_text( Ink_ComboBoxEntry_Action* action ) { - - gchar* text = g_strdup( action->text ); - return text; -} - -/* - * For the font-family list we need to handle two cases: - * Text is in list store: - * In this case we use row number as the font-family list can have duplicate - * entries, one in the document font part and one in the system font part. In - * order that scrolling through the list works properly we must distinguish - * between the two. - * Text is not in the list store (i.e. default font-family is not on system): - * In this case we have a row number of -1, and the text must be set by hand. - */ -gboolean ink_comboboxentry_action_set_active_text( Ink_ComboBoxEntry_Action* action, const gchar* text, int row ) { - - if( strcmp( action->text, text ) != 0 ) { - g_free( action->text ); - action->text = g_strdup( text ); - } - - // Get active row or -1 if none - if( row < 0 ) { - row = get_active_row_from_text( action, action->text ); - } - action->active = row; - - // Set active row, check that combobox has been created. - if( action->combobox ) { - gtk_combo_box_set_active( GTK_COMBO_BOX( action->combobox ), action->active ); - } - - // Fiddle with entry - if( action->entry ) { - - // Explicitly set text in GtkEntry box (won't be set if text not in list). - gtk_entry_set_text( action->entry, text ); - - // Show or hide warning -- this might be better moved to text-toolbox.cpp - if( action->info_cb_id != 0 && - !action->info_cb_blocked ) { - g_signal_handler_block (G_OBJECT(action->entry), - action->info_cb_id ); - action->info_cb_blocked = true; - } - if( action->warning_cb_id != 0 && - !action->warning_cb_blocked ) { - g_signal_handler_block (G_OBJECT(action->entry), - action->warning_cb_id ); - action->warning_cb_blocked = true; - } - - bool set = false; - if( action->warning != nullptr ) { - Glib::ustring missing = check_comma_separated_text( action ); - if( !missing.empty() ) { - gtk_entry_set_icon_from_icon_name( action->entry, - GTK_ENTRY_ICON_SECONDARY, - INKSCAPE_ICON("dialog-warning") ); - // Can't add tooltip until icon set - Glib::ustring warning = action->warning; - warning += ": "; - warning += missing; - gtk_entry_set_icon_tooltip_text( action->entry, - GTK_ENTRY_ICON_SECONDARY, - warning.c_str() ); - - if( action->warning_cb ) { - - // Add callback if we haven't already - if( action->warning_cb_id == 0 ) { - action->warning_cb_id = - g_signal_connect( G_OBJECT(action->entry), - "icon-press", - G_CALLBACK(action->warning_cb), - action); - } - // Unblock signal - if( action->warning_cb_blocked ) { - g_signal_handler_unblock (G_OBJECT(action->entry), - action->warning_cb_id ); - action->warning_cb_blocked = false; - } - } - set = true; - } - } - - if( !set && action->info != nullptr ) { - gtk_entry_set_icon_from_icon_name( GTK_ENTRY(action->entry), - GTK_ENTRY_ICON_SECONDARY, - INKSCAPE_ICON("edit-select-all") ); - gtk_entry_set_icon_tooltip_text( action->entry, - GTK_ENTRY_ICON_SECONDARY, - action->info ); - - if( action->info_cb ) { - // Add callback if we haven't already - if( action->info_cb_id == 0 ) { - action->info_cb_id = - g_signal_connect( G_OBJECT(action->entry), - "icon-press", - G_CALLBACK(action->info_cb), - action); - } - // Unblock signal - if( action->info_cb_blocked ) { - g_signal_handler_unblock (G_OBJECT(action->entry), - action->info_cb_id ); - action->info_cb_blocked = false; - } - } - set = true; - } - - if( !set ) { - gtk_entry_set_icon_from_icon_name( GTK_ENTRY(action->entry), - GTK_ENTRY_ICON_SECONDARY, - nullptr ); - } - } - - // Return if active text in list - gboolean found = ( action->active != -1 ); - return found; -} - -void ink_comboboxentry_action_set_entry_width( Ink_ComboBoxEntry_Action* action, gint entry_width ) { - - action->entry_width = entry_width; - - // Widget may not have been created.... - if( action->entry ) { - gtk_entry_set_width_chars( GTK_ENTRY(action->entry), entry_width ); - } -} - -void ink_comboboxentry_action_set_extra_width( Ink_ComboBoxEntry_Action* action, gint extra_width ) { - - action->extra_width = extra_width; - - // Widget may not have been created.... - if( action->combobox ) { - GtkRequisition req; - gtk_widget_get_preferred_size(GTK_WIDGET(action->combobox), &req, nullptr); - gtk_widget_set_size_request( GTK_WIDGET( action->combobox ), req.width + action->extra_width, -1 ); - } -} - -void ink_comboboxentry_action_popup_enable( Ink_ComboBoxEntry_Action* action ) { - - action->popup = true; - - // Widget may not have been created.... - if( action->entry ) { - - // Check we don't already have a GtkEntryCompletion - if( action->entry_completion ) return; - - action->entry_completion = gtk_entry_completion_new(); - - gtk_entry_set_completion( action->entry, action->entry_completion ); - gtk_entry_completion_set_model( action->entry_completion, action->model ); - gtk_entry_completion_set_text_column( action->entry_completion, 0 ); - gtk_entry_completion_set_popup_completion( action->entry_completion, true ); - gtk_entry_completion_set_inline_completion( action->entry_completion, false ); - gtk_entry_completion_set_inline_selection( action->entry_completion, true ); - - g_signal_connect (G_OBJECT (action->entry_completion), "match-selected", G_CALLBACK (match_selected_cb), action ); - - - } -} - -void ink_comboboxentry_action_popup_disable( Ink_ComboBoxEntry_Action* action ) { - - action->popup = false; - - if( action->entry_completion ) { - gtk_widget_destroy(GTK_WIDGET(action->entry_completion)); - action->entry_completion = nullptr; - } -} -void ink_comboboxentry_action_set_tooltip( Ink_ComboBoxEntry_Action* action, const gchar* tooltip ) { - - // Widget may not have been created.... - if( action->entry ) { - gtk_widget_set_tooltip_text ( GTK_WIDGET(action->entry), tooltip); - } - if( action->combobox ) { - gtk_widget_set_tooltip_text ( GTK_WIDGET(action->combobox), tooltip); - } - -} - -void ink_comboboxentry_action_set_info( Ink_ComboBoxEntry_Action* action, const gchar* info ) { - - g_free( action->info ); - action->info = g_strdup( info ); - - // Widget may not have been created.... - if( action->entry ) { - gtk_entry_set_icon_tooltip_text( GTK_ENTRY(action->entry), - GTK_ENTRY_ICON_SECONDARY, - action->info ); - } -} - -void ink_comboboxentry_action_set_info_cb( Ink_ComboBoxEntry_Action* action, gpointer info_cb ) { - - action->info_cb = info_cb; -} - -void ink_comboboxentry_action_set_warning( Ink_ComboBoxEntry_Action* action, const gchar* warning ) { - - g_free( action->warning ); - action->warning = g_strdup( warning ); - - // Widget may not have been created.... - if( action->entry ) { - gtk_entry_set_icon_tooltip_text( GTK_ENTRY(action->entry), - GTK_ENTRY_ICON_SECONDARY, - action->warning ); - } -} - -void ink_comboboxentry_action_set_warning_cb( Ink_ComboBoxEntry_Action* action, gpointer warning_cb ) { - - action->warning_cb = warning_cb; -} - -void ink_comboboxentry_action_set_altx_name( Ink_ComboBoxEntry_Action* action, const gchar* altx_name ) { - - g_free( action->altx_name ); - action->altx_name = g_strdup( altx_name ); - - // Widget may not have been created.... - if( action->entry ) { - g_object_set_data( G_OBJECT(action->entry), action->altx_name, action->entry ); - } -} - -// Internal --------------------------------------------------- - -// Return row of active text or -1 if not found. If exclude is true, -// use 3d colunm if available to exclude row from checking (useful to -// skip rows added for font-families included in doc and not on -// system) -gint get_active_row_from_text( Ink_ComboBoxEntry_Action* action, const gchar* target_text, - gboolean exclude, gboolean ignore_case ) { - - // Check if text in list - gint row = 0; - gboolean found = false; - GtkTreeIter iter; - gboolean valid = gtk_tree_model_get_iter_first( action->model, &iter ); - while ( valid ) { - - // See if we should exclude a row - gboolean check = true; // If true, font-family is on system. - if( exclude && gtk_tree_model_get_n_columns( action->model ) > 2 ) { - gtk_tree_model_get( action->model, &iter, 2, &check, -1 ); - } - - if( check ) { - // Get text from list entry - gchar* text = nullptr; - gtk_tree_model_get( action->model, &iter, 0, &text, -1 ); // Column 0 - - if( !ignore_case ) { - // Case sensitive compare - if( strcmp( target_text, text ) == 0 ){ - found = true; - break; - } - } else { - // Case insensitive compare - gchar* target_text_casefolded = g_utf8_casefold( target_text, -1 ); - gchar* text_casefolded = g_utf8_casefold( text, -1 ); - gboolean equal = (strcmp( target_text_casefolded, text_casefolded ) == 0 ); - g_free( text_casefolded ); - g_free( target_text_casefolded ); - if( equal ) { - found = true; - break; - } - } - } - - ++row; - valid = gtk_tree_model_iter_next( action->model, &iter ); - } - - if( !found ) row = -1; - - return row; - -} - -// Checks if all comma separated text fragments are in the list and -// returns a ustring with a list of missing fragments. -// This is useful for checking if all fonts in a font-family fallback -// list are available on the system. -// -// This routine could also create a Pango Markup string to show which -// fragments are invalid in the entry box itself. See: -// http://developer.gnome.org/pango/stable/PangoMarkupFormat.html -// However... it appears that while one can retrieve the PangoLayout -// for a GtkEntry box, it is only a copy and changing it has no effect. -// PangoLayout * pl = gtk_entry_get_layout( entry ); -// pango_layout_set_markup( pl, "NEW STRING", -1 ); // DOESN'T WORK -static Glib::ustring check_comma_separated_text( Ink_ComboBoxEntry_Action* action ) { - - Glib::ustring missing; - - // Parse fallback_list using a comma as deliminator - gchar** tokens = g_strsplit( action->text, ",", 0 ); - - gint i = 0; - while( tokens[i] != nullptr ) { - - // Remove any surrounding white space. - g_strstrip( tokens[i] ); - - if( get_active_row_from_text( action, tokens[i], true, true ) == -1 ) { - missing += tokens[i]; - missing += ", "; - } - ++i; - } - g_strfreev( tokens ); - - // Remove extra comma and space from end. - if( missing.size() >= 2 ) { - missing.resize( missing.size()-2 ); - } - return missing; -} - -// Callbacks --------------------------------------------------- - -static void combo_box_changed_cb( GtkComboBox* widget, gpointer data ) { - - // Two things can happen to get here: - // An item is selected in the drop-down menu. - // Text is typed. - // We only react here if an item is selected. - - // Get action - Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION( data ); - - // Check if item selected: - gint newActive = gtk_combo_box_get_active(widget); - if( newActive >= 0 && newActive != action->active ) { - - action->active = newActive; - - GtkTreeIter iter; - if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX( action->combobox ), &iter ) ) { - - gchar* text = nullptr; - gtk_tree_model_get( action->model, &iter, 0, &text, -1 ); - gtk_entry_set_text( action->entry, text ); - - g_free( action->text ); - action->text = text; - } - - // Now let the world know - g_signal_emit( G_OBJECT(action), signals[CHANGED], 0 ); - } -} - -static void entry_activate_cb( GtkEntry* widget, gpointer data ) { - - // Get text from entry box.. check if it matches a menu entry. - - // Get action - Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION( data ); - - // Get text - g_free( action->text ); - action->text = g_strdup( gtk_entry_get_text( widget ) ); - - // Get row - action->active = - get_active_row_from_text( action, action->text ); - - // Set active row - gtk_combo_box_set_active( GTK_COMBO_BOX( action->combobox), action->active ); - - // Now let the world know - g_signal_emit( G_OBJECT(action), signals[CHANGED], 0 ); - -} - -static gboolean match_selected_cb( GtkEntryCompletion* /*widget*/, GtkTreeModel* model, GtkTreeIter* iter, gpointer data ) -{ - // Get action - Ink_ComboBoxEntry_Action *action = INK_COMBOBOXENTRY_ACTION( data ); - GtkEntry *entry = action->entry; - - if( entry) { - gchar *family = nullptr; - gtk_tree_model_get(model, iter, 0, &family, -1); - - // Set text in GtkEntry - gtk_entry_set_text (GTK_ENTRY (entry), family ); - - // Set text in GtkAction - g_free( action->text ); - action->text = family; - - // Get row - action->active = - get_active_row_from_text( action, action->text ); - - // Set active row - gtk_combo_box_set_active( GTK_COMBO_BOX( action->combobox), action->active ); - - // Now let the world know - g_signal_emit( G_OBJECT(action), signals[CHANGED], 0 ); - - return true; - } - return false; -} - -static void ink_comboboxentry_action_defocus( Ink_ComboBoxEntry_Action* action ) -{ - if ( action->focusWidget ) { - gtk_widget_grab_focus( action->focusWidget ); - } -} - -gboolean keypress_cb( GtkWidget * /*widget*/, GdkEventKey *event, gpointer data ) -{ - gboolean wasConsumed = FALSE; /* default to report event not consumed */ - guint key = 0; - Ink_ComboBoxEntry_Action* action = INK_COMBOBOXENTRY_ACTION( data ); - gdk_keymap_translate_keyboard_state( Gdk::Display::get_default()->get_keymap(), - event->hardware_keycode, (GdkModifierType)event->state, - 0, &key, nullptr, nullptr, nullptr ); - - switch ( key ) { - - // TODO Add bindings for Tab/LeftTab - case GDK_KEY_Escape: - { - //gtk_spin_button_set_value( GTK_SPIN_BUTTON(widget), action->private_data->lastVal ); - ink_comboboxentry_action_defocus( action ); - wasConsumed = TRUE; - } - break; - - case GDK_KEY_Return: - case GDK_KEY_KP_Enter: - { - ink_comboboxentry_action_defocus( action ); - //wasConsumed = TRUE; - } - break; - - - } - - return wasConsumed; -} - -/* - 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/ink-comboboxentry-action.h b/src/widgets/ink-comboboxentry-action.h deleted file mode 100644 index fa7dd5cdf..000000000 --- a/src/widgets/ink-comboboxentry-action.h +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * A subclass of GtkAction that wraps a GtkComboBoxEntry. - * Features: - * Setting GtkEntryBox width in characters. - * Passing a function for formatting cells. - * Displaying a warning if text isn't in list. - * Setting names for GtkComboBoxEntry and GtkEntry (actionName_combobox, actionName_entry) - * to allow setting resources. - * - * Author(s): - * Tavmjong Bah - * Jon A. Cruz <jon@joncruz.org> - * - * Copyright (C) 2010 Authors - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - -#ifndef SEEN_INK_COMBOBOXENTRY_ACTION -#define SEEN_INK_COMBOBOXENTRY_ACTION - -#include <gtk/gtk.h> - -#define INK_COMBOBOXENTRY_TYPE_ACTION (ink_comboboxentry_action_get_type()) -#define INK_COMBOBOXENTRY_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INK_COMBOBOXENTRY_TYPE_ACTION, Ink_ComboBoxEntry_Action)) -#define INK_COMBOBOXENTRY_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INK_COMBOBOXENTRY_TYPE_ACTION, Ink_ComboBoxEntry_ActionClass)) -#define INK_COMBOBOXENTRY_IS_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INK_COMBOBOXENTRY_TYPE_ACTION)) -#define INK_COMBOBOXENTRY_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INK_COMBOBOXENTRY_TYPE_ACTION, Ink_ComboBoxEntry_ActionClass)) - -typedef struct _Ink_ComboBoxEntry_ActionClass Ink_ComboBoxEntry_ActionClass; -typedef struct _Ink_ComboBoxEntry_Action Ink_ComboBoxEntry_Action; - -struct _Ink_ComboBoxEntry_ActionClass { - GtkActionClass parent_class; - - void (*changed) (Ink_ComboBoxEntry_Action* action); - void (*activated) (Ink_ComboBoxEntry_Action* action); -}; - -struct _Ink_ComboBoxEntry_Action { - GtkAction parent_instance; - - GtkTreeModel *model; - GtkComboBox *combobox; - GtkEntry *entry; - GtkEntryCompletion *entry_completion; - GtkWidget *indicator; - - gpointer cell_data_func; // drop-down menu format - gpointer separator_func; - - gint active; // Index of active menu item (-1 if not in list). - gchar *text; // Text of active menu item or entry box. - gint entry_width;// Width of GtkEntry in characters. - gint extra_width;// Extra Width of GtkComboBox.. to widen drop-down list in list mode. - gboolean popup; // Do we pop-up an entry-completion dialog? - gchar *info; // Text for tooltip info about entry. - gpointer info_cb; // Callback for clicking info icon. - gint info_cb_id; - gboolean info_cb_blocked; - gchar *warning; // Text for tooltip warning that entry isn't in list. - gpointer warning_cb; // Callback for clicking warning icon. - gint warning_cb_id; - gboolean warning_cb_blocked; - gchar *altx_name; // Target for Alt-X keyboard shortcut. - GtkWidget *focusWidget; -}; - - -GType ink_comboboxentry_action_get_type (); - -/** - * Creates a GtkAction subclass that wraps a GtkComboBoxEntry object. - */ -Ink_ComboBoxEntry_Action *ink_comboboxentry_action_new ( const gchar *name, - const gchar *label, - const gchar *tooltip, - const gchar *stock_id, - GtkTreeModel *model, - gint entry_width = -1, - gint extra_width = -1, - gpointer cell_data_func = nullptr, - gpointer separator_func = nullptr, - GtkWidget* focusWidget = nullptr); - -GtkTreeModel *ink_comboboxentry_action_get_model( Ink_ComboBoxEntry_Action* action ); -GtkComboBox *ink_comboboxentry_action_get_comboboxentry( Ink_ComboBoxEntry_Action* action ); - -gchar* ink_comboboxentry_action_get_active_text( Ink_ComboBoxEntry_Action* action ); -gboolean ink_comboboxentry_action_set_active_text( Ink_ComboBoxEntry_Action* action, const gchar* text, int row=-1 ); - -void ink_comboboxentry_action_set_entry_width( Ink_ComboBoxEntry_Action* action, gint entry_width ); -void ink_comboboxentry_action_set_extra_width( Ink_ComboBoxEntry_Action* action, gint extra_width ); - -void ink_comboboxentry_action_popup_enable( Ink_ComboBoxEntry_Action* action ); -void ink_comboboxentry_action_popup_disable( Ink_ComboBoxEntry_Action* action ); - -void ink_comboboxentry_action_set_info( Ink_ComboBoxEntry_Action* action, const gchar* info ); -void ink_comboboxentry_action_set_info_cb( Ink_ComboBoxEntry_Action* action, gpointer info_cb ); -void ink_comboboxentry_action_set_warning( Ink_ComboBoxEntry_Action* action, const gchar* warning_cb ); -void ink_comboboxentry_action_set_warning_cb(Ink_ComboBoxEntry_Action* action, gpointer warning ); -void ink_comboboxentry_action_set_tooltip( Ink_ComboBoxEntry_Action* action, const gchar* tooltip ); - -void ink_comboboxentry_action_set_altx_name( Ink_ComboBoxEntry_Action* action, const gchar* altx_name ); - -#endif /* SEEN_INK_COMBOBOXENTRY_ACTION */ diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index b3f25c764..10a24a0d1 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -60,7 +60,6 @@ #include "ui/widget/style-swatch.h" #include "ui/widget/unit-tracker.h" -#include "widgets/ege-adjustment-action.h" #include "widgets/spinbutton-events.h" #include "widgets/spw-utilities.h" #include "widgets/widget-sizes.h" @@ -182,63 +181,64 @@ static struct { gchar const *type_name; gchar const *data_name; GtkWidget *(*create_func)(SPDesktop *desktop); - GtkWidget *(*prep_func)(SPDesktop *desktop, GtkActionGroup* mainActions); gchar const *ui_name; gint swatch_verb_id; gchar const *swatch_tool; gchar const *swatch_tip; } const aux_toolboxes[] = { - { "/tools/select", "select_toolbox", Inkscape::UI::Toolbar::SelectToolbar::create, nullptr, "SelectToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/nodes", "node_toolbox", Inkscape::UI::Toolbar::NodeToolbar::create, nullptr, "NodeToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/tweak", "tweak_toolbox", Inkscape::UI::Toolbar::TweakToolbar::create, nullptr, "TweakToolbar", - SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")}, - { "/tools/spray", "spray_toolbox", Inkscape::UI::Toolbar::SprayToolbar::create, nullptr, "SprayToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/zoom", "zoom_toolbox", Inkscape::UI::Toolbar::ZoomToolbar::create, nullptr, "ZoomToolbar", - SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/select", "select_toolbox", Inkscape::UI::Toolbar::SelectToolbar::create, "SelectToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/nodes", "node_toolbox", Inkscape::UI::Toolbar::NodeToolbar::create, "NodeToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/tweak", "tweak_toolbox", Inkscape::UI::Toolbar::TweakToolbar::create, "TweakToolbar", + SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")}, + { "/tools/spray", "spray_toolbox", Inkscape::UI::Toolbar::SprayToolbar::create, "SprayToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/zoom", "zoom_toolbox", Inkscape::UI::Toolbar::ZoomToolbar::create, "ZoomToolbar", + SP_VERB_INVALID, nullptr, nullptr}, // If you change MeasureToolbar here, change it also in desktop-widget.cpp - { "/tools/measure", "measure_toolbox", Inkscape::UI::Toolbar::MeasureToolbar::create, nullptr, "MeasureToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/shapes/star", "star_toolbox", Inkscape::UI::Toolbar::StarToolbar::create, nullptr, "StarToolbar", - SP_VERB_CONTEXT_STAR_PREFS, "/tools/shapes/star", N_("Style of new stars")}, - { "/tools/shapes/rect", "rect_toolbox", Inkscape::UI::Toolbar::RectToolbar::create, nullptr, "RectToolbar", - SP_VERB_CONTEXT_RECT_PREFS, "/tools/shapes/rect", N_("Style of new rectangles")}, - { "/tools/shapes/3dbox", "3dbox_toolbox", Inkscape::UI::Toolbar::Box3DToolbar::create, nullptr, "3DBoxToolbar", - SP_VERB_CONTEXT_3DBOX_PREFS, "/tools/shapes/3dbox", N_("Style of new 3D boxes")}, - { "/tools/shapes/arc", "arc_toolbox", Inkscape::UI::Toolbar::ArcToolbar::create, nullptr, "ArcToolbar", - SP_VERB_CONTEXT_ARC_PREFS, "/tools/shapes/arc", N_("Style of new ellipses")}, - { "/tools/shapes/spiral", "spiral_toolbox", Inkscape::UI::Toolbar::SpiralToolbar::create, nullptr, "SpiralToolbar", - SP_VERB_CONTEXT_SPIRAL_PREFS, "/tools/shapes/spiral", N_("Style of new spirals")}, - { "/tools/freehand/pencil", "pencil_toolbox", Inkscape::UI::Toolbar::PencilToolbar::create_pencil, nullptr, "PencilToolbar", - SP_VERB_CONTEXT_PENCIL_PREFS, "/tools/freehand/pencil", N_("Style of new paths created by Pencil")}, - { "/tools/freehand/pen", "pen_toolbox", Inkscape::UI::Toolbar::PencilToolbar::create_pen, nullptr, "PenToolbar", - SP_VERB_CONTEXT_PEN_PREFS, "/tools/freehand/pen", N_("Style of new paths created by Pen")}, - { "/tools/calligraphic", "calligraphy_toolbox", Inkscape::UI::Toolbar::CalligraphyToolbar::create, nullptr, "CalligraphyToolbar", - SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "/tools/calligraphic", N_("Style of new calligraphic strokes")}, - { "/tools/eraser", "eraser_toolbox", Inkscape::UI::Toolbar::EraserToolbar::create, nullptr, "EraserToolbar", - SP_VERB_CONTEXT_ERASER_PREFS, "/tools/eraser", _("TBD")}, - { "/tools/lpetool", "lpetool_toolbox", Inkscape::UI::Toolbar::LPEToolbar::create, nullptr, "LPEToolToolbar", - SP_VERB_CONTEXT_LPETOOL_PREFS, "/tools/lpetool", _("TBD")}, + { "/tools/measure", "measure_toolbox", Inkscape::UI::Toolbar::MeasureToolbar::create, "MeasureToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/shapes/star", "star_toolbox", Inkscape::UI::Toolbar::StarToolbar::create, "StarToolbar", + SP_VERB_CONTEXT_STAR_PREFS, "/tools/shapes/star", N_("Style of new stars")}, + { "/tools/shapes/rect", "rect_toolbox", Inkscape::UI::Toolbar::RectToolbar::create, "RectToolbar", + SP_VERB_CONTEXT_RECT_PREFS, "/tools/shapes/rect", N_("Style of new rectangles")}, + { "/tools/shapes/3dbox", "3dbox_toolbox", Inkscape::UI::Toolbar::Box3DToolbar::create, "3DBoxToolbar", + SP_VERB_CONTEXT_3DBOX_PREFS, "/tools/shapes/3dbox", N_("Style of new 3D boxes")}, + { "/tools/shapes/arc", "arc_toolbox", Inkscape::UI::Toolbar::ArcToolbar::create, "ArcToolbar", + SP_VERB_CONTEXT_ARC_PREFS, "/tools/shapes/arc", N_("Style of new ellipses")}, + { "/tools/shapes/spiral", "spiral_toolbox", Inkscape::UI::Toolbar::SpiralToolbar::create, "SpiralToolbar", + SP_VERB_CONTEXT_SPIRAL_PREFS, "/tools/shapes/spiral", N_("Style of new spirals")}, + { "/tools/freehand/pencil", "pencil_toolbox", Inkscape::UI::Toolbar::PencilToolbar::create_pencil, "PencilToolbar", + SP_VERB_CONTEXT_PENCIL_PREFS, "/tools/freehand/pencil", N_("Style of new paths created by Pencil")}, + { "/tools/freehand/pen", "pen_toolbox", Inkscape::UI::Toolbar::PencilToolbar::create_pen, "PenToolbar", + SP_VERB_CONTEXT_PEN_PREFS, "/tools/freehand/pen", N_("Style of new paths created by Pen")}, + { "/tools/calligraphic", "calligraphy_toolbox", Inkscape::UI::Toolbar::CalligraphyToolbar::create, "CalligraphyToolbar", + SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS, "/tools/calligraphic", N_("Style of new calligraphic strokes")}, + { "/tools/eraser", "eraser_toolbox", Inkscape::UI::Toolbar::EraserToolbar::create, "EraserToolbar", + SP_VERB_CONTEXT_ERASER_PREFS, "/tools/eraser", _("TBD")}, + { "/tools/lpetool", "lpetool_toolbox", Inkscape::UI::Toolbar::LPEToolbar::create, "LPEToolToolbar", + SP_VERB_CONTEXT_LPETOOL_PREFS, "/tools/lpetool", _("TBD")}, // If you change TextToolbar here, change it also in desktop-widget.cpp - { "/tools/text", "text_toolbox", nullptr, Inkscape::UI::Toolbar::TextToolbar::prep, "TextToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/dropper", "dropper_toolbox", Inkscape::UI::Toolbar::DropperToolbar::create, nullptr, "DropperToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/connector", "connector_toolbox", Inkscape::UI::Toolbar::ConnectorToolbar::create, nullptr, "ConnectorToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/gradient", "gradient_toolbox", Inkscape::UI::Toolbar::GradientToolbar::create, nullptr, "GradientToolbar", - SP_VERB_INVALID, nullptr, nullptr}, - { "/tools/mesh", "mesh_toolbox", Inkscape::UI::Toolbar::MeshToolbar::create, nullptr, "MeshToolbar", - SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/text", "text_toolbox", Inkscape::UI::Toolbar::TextToolbar::create, "TextToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/dropper", "dropper_toolbox", Inkscape::UI::Toolbar::DropperToolbar::create, "DropperToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/connector", "connector_toolbox", Inkscape::UI::Toolbar::ConnectorToolbar::create, "ConnectorToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/gradient", "gradient_toolbox", Inkscape::UI::Toolbar::GradientToolbar::create, "GradientToolbar", + SP_VERB_INVALID, nullptr, nullptr}, + { "/tools/mesh", "mesh_toolbox", Inkscape::UI::Toolbar::MeshToolbar::create, "MeshToolbar", + SP_VERB_INVALID, nullptr, nullptr}, #if HAVE_POTRACE - { "/tools/paintbucket", "paintbucket_toolbox", Inkscape::UI::Toolbar::PaintbucketToolbar::create, nullptr, "PaintbucketToolbar", - SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")}, + { "/tools/paintbucket", "paintbucket_toolbox", Inkscape::UI::Toolbar::PaintbucketToolbar::create, "PaintbucketToolbar", + SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")}, #else - { "/tools/paintbucket", "paintbucket_toolbox", nullptr, nullptr, "PaintbucketToolbar", SP_VERB_NONE, "/tools/paintbucket", N_("Disabled")}, + { "/tools/paintbucket", "paintbucket_toolbox", nullptr, "PaintbucketToolbar", + SP_VERB_NONE, "/tools/paintbucket", N_("Disabled")}, #endif - { nullptr, nullptr, nullptr, nullptr, nullptr, SP_VERB_INVALID, nullptr, nullptr } + { nullptr, nullptr, nullptr, nullptr, + SP_VERB_INVALID, nullptr, nullptr } }; @@ -464,55 +464,6 @@ static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRa return widget; } -EgeAdjustmentAction * create_adjustment_action( gchar const *name, - gchar const *label, gchar const *shortLabel, gchar const *tooltip, - Glib::ustring const &path, gdouble def, - gboolean altx, gchar const *altx_mark, - gdouble lower, gdouble upper, gdouble step, gdouble page, - gchar const** descrLabels, gdouble const* descrValues, guint descrCount, - Inkscape::UI::Widget::UnitTracker *unit_tracker, - gdouble climb/* = 0.1*/, guint digits/* = 3*/, double factor/* = 1.0*/ ) -{ - static bool init = false; - if ( !init ) { - init = true; - ege_adjustment_action_set_compact_tool_factory( createCustomSlider ); - } - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( prefs->getDouble(path, def) * factor, - lower, upper, step, page, 0 ) ); - - EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, label, tooltip, nullptr, climb, digits, unit_tracker ); - if ( shortLabel ) { - g_object_set( act, "short_label", shortLabel, NULL ); - } - - if ( (descrCount > 0) && descrLabels && descrValues ) { - ege_adjustment_action_set_descriptions( act, descrLabels, descrValues, descrCount ); - } - - // The EgeAdjustmentAction class uses this to create a data member - // with the specified name, that simply points to the object itself. - // It appears to only be used by the DesktopWidget to find the named - // object - // - // TODO: Get rid of this and look up widgets by name instead. - if ( altx && altx_mark ) { - g_object_set( G_OBJECT(act), "self-id", altx_mark, NULL ); - } - - if (unit_tracker) { - unit_tracker->addAdjustment(adj); - } - - // Using a cast just to make sure we pass in the right kind of function pointer - g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL ); - - return act; -} - - void ToolboxFactory::setToolboxDesktop(GtkWidget *toolbox, SPDesktop *desktop) { sigc::connection *conn = static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), @@ -723,60 +674,20 @@ void update_tool_toolbox( SPDesktop *desktop, ToolBase *eventcontext, GtkWidget * * \details This is the one that appears below the main menu, and contains * tool-specific toolbars. Each toolbar is created here, using - * either: - * * Its "create" method - this directly prepares a GtkToolbar - * widget, containing all the tools, or - * * Its "prep" method - this defines a set of GtkActions, which - * are later used to populate a toolbar. + * its "create" method. + * * The actual method used for each toolbar is specified in the * "aux_toolboxes" array, defined above. - * - * \todo Needs to be rewritten so that GtkActions and GtkUIManager - * are not used. This means that the "prep" approach is deprecated - * and we should adapt all toolbars to have a "create" method instead. */ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); GtkSizeGroup* grouper = gtk_size_group_new( GTK_SIZE_GROUP_BOTH ); - Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop ); - - // The UI Manager creates widgets based on the definitions in the - // "toolbar-select.ui" file. This is only used with the "prep" - // method of toolbar-creation - GtkUIManager* mgr = gtk_ui_manager_new(); - GError *err = nullptr; - gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 ); - Glib::ustring filename = get_filename(UIS, "toolbar-select.ui"); - guint ret = gtk_ui_manager_add_ui_from_file(mgr, filename.c_str(), &err); - if(err) { - g_warning("Failed to load aux toolbar %s: %s", filename.c_str(), err->message); - g_error_free(err); - return; - } - - // For the "prep" method, we create a "fake" set of toolbars - // that just contain a set of GtkActions. These are stored - // in the "dataHolders" map. - std::map<std::string, GtkWidget*> dataHolders; // Loop through all the toolboxes and create them using either - // their "prep" or "create" methods. + // their "create" methods. for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) { - if ( aux_toolboxes[i].prep_func ) { - - // For the "prep" method, create a "fake" toolbar - // that only contains a set of GtkActions. In other - // words, this doesn't actually show anything... it - // just defines behaviour. - GtkWidget* kludge = aux_toolboxes[i].prep_func(desktop, mainActions->gobj()); - gtk_widget_set_name( kludge, "Kludge" ); - dataHolders[aux_toolboxes[i].type_name] = kludge; - } else if (aux_toolboxes[i].create_func) { - - // For the "create" method, directly create a "real" toolbar, - // which contains visible, fully functional widgets. Note that - // this should also contain any swatches that are needed. + if (aux_toolboxes[i].create_func) { GtkWidget *sub_toolbox = aux_toolboxes[i].create_func(desktop); gtk_widget_set_name( sub_toolbox, "SubToolBox" ); @@ -824,78 +735,6 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) } } - // Second pass to create toolbars *after* all GtkActions are created - // This is only used for toolbars that are being created using the "prep" - // method - for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) { - if ( aux_toolboxes[i].prep_func ) { - - // Get the previously created "fake" toolbar that just contains - // invisible GtkAction definitions - auto kludge = dataHolders[aux_toolboxes[i].type_name]; - - // The thing that we put into the toolbox is actually a GtkGrid. - // It contains three elements... from left-to-right: - // * A "real" toolbar containing all the visible, fully functional - // widgets - // * (optionally) A swatch widget for use with that toolbar - // * The "fake" toolbar containing the action definitions, which we - // created previously - auto holder = gtk_grid_new(); - gtk_widget_set_name( holder, aux_toolboxes[i].ui_name ); - - // First pack the "fake" toolbar with the action definitions - gtk_grid_attach( GTK_GRID(holder), kludge, 2, 0, 1, 1); - - // Now, use the UI Manager to create a "real" toolbar. This works - // because the actions needed by the UI file have all been defined - // in the "fake" toolbar - gchar* tmp = g_strdup_printf( "/ui/%s", aux_toolboxes[i].ui_name ); - GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, tmp ); - g_free( tmp ); - tmp = nullptr; - - // This part is just for styling - if ( prefs->getBool( "/toolbox/icononly", true) ) { - gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS ); - } - - GtkIconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small"); - gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) ); - gtk_widget_set_hexpand(toolBar, TRUE); - gtk_grid_attach( GTK_GRID(holder), toolBar, 0, 0, 1, 1); - - // Add a swatch widget if one was specified - if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) { - Inkscape::UI::Widget::StyleSwatch *swatch = new Inkscape::UI::Widget::StyleSwatch( nullptr, _(aux_toolboxes[i].swatch_tip) ); - swatch->setDesktop( desktop ); - swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id ); - swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true ); - swatch->set_margin_start(AUX_BETWEEN_BUTTON_GROUPS); - swatch->set_margin_end(AUX_BETWEEN_BUTTON_GROUPS); - swatch->set_margin_top(AUX_SPACING); - swatch->set_margin_bottom(AUX_SPACING); - - auto swatch_ = GTK_WIDGET( swatch->gobj() ); - gtk_grid_attach( GTK_GRID(holder), swatch_, 1, 0, 1, 1); - } - if(i==0){ - gtk_widget_show_all( holder ); - } else { - gtk_widget_show_now( holder ); - } - sp_set_font_size_smaller( holder ); - - gtk_size_group_add_widget( grouper, holder ); - - // Finally add the grid to the toolbox. - // As described above, a pointer is also stored so that toolbars can be - // switched later. - gtk_container_add( GTK_CONTAINER(toolbox), holder ); - g_object_set_data( G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder ); - } - } - g_object_unref( G_OBJECT(grouper) ); } diff --git a/src/widgets/toolbox.h b/src/widgets/toolbox.h index f396f4d9a..3a1bb4cc3 100644 --- a/src/widgets/toolbox.h +++ b/src/widgets/toolbox.h @@ -20,8 +20,6 @@ #define TOOLBAR_SLIDER_HINT "compact" -typedef struct _EgeAdjustmentAction EgeAdjustmentAction; - class SPDesktop; namespace Inkscape { @@ -72,18 +70,6 @@ public: } // namespace UI } // namespace Inkscape - -// utility - - EgeAdjustmentAction * create_adjustment_action( gchar const *name, - gchar const *label, gchar const *shortLabel, gchar const *tooltip, - Glib::ustring const &path, gdouble def, - gboolean altx, gchar const *altx_mark, - gdouble lower, gdouble upper, gdouble step, gdouble page, - gchar const** descrLabels, gdouble const* descrValues, guint descrCount, - Inkscape::UI::Widget::UnitTracker *unit_tracker = nullptr, - gdouble climb = 0.1, guint digits = 3, double factor = 1.0 ); - #endif /* !SEEN_TOOLBOX_H */ /* |
