diff options
Diffstat (limited to '')
-rw-r--r-- | src/widgets/toolbox.cpp | 842 |
1 files changed, 842 insertions, 0 deletions
diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp new file mode 100644 index 0000000..6248dec --- /dev/null +++ b/src/widgets/toolbox.cpp @@ -0,0 +1,842 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/** + * @file + * Inkscape toolbar definitions and general utility functions. + * Each tool should have its own xxx-toolbar implementation file + */ +/* Authors: + * MenTaLguY <mental@rydia.net> + * Lauris Kaplinski <lauris@kaplinski.com> + * bulia byak <buliabyak@users.sf.net> + * Frank Felfe <innerspace@iname.com> + * John Cliff <simarilius@yahoo.com> + * David Turner <novalis@gnu.org> + * Josh Andler <scislac@scislac.com> + * Jon A. Cruz <jon@joncruz.org> + * Maximilian Albert <maximilian.albert@gmail.com> + * Tavmjong Bah <tavmjong@free.fr> + * Abhishek Sharma + * Kris De Gussem <Kris.DeGussem@gmail.com> + * Jabiertxo Arraiza <jabier.arraiza@marker.es> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2015 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <gtkmm/box.h> +#include <gtkmm/action.h> +#include <gtkmm/actiongroup.h> +#include <gtkmm/toolitem.h> +#include <glibmm/i18n.h> + +#include "desktop-style.h" +#include "desktop.h" +#include "document-undo.h" +#include "inkscape.h" +#include "verbs.h" + +#include "ink-action.h" + +#include "helper/action.h" +#include "helper/verb-action.h" + +#include "include/gtkmm_version.h" + +#include "io/resource.h" + +#include "object/sp-namedview.h" + +#include "ui/icon-names.h" +#include "ui/tools-switch.h" +#include "ui/uxmanager.h" +#include "ui/widget/button.h" +#include "ui/widget/spinbutton.h" +#include "ui/widget/style-swatch.h" +#include "ui/widget/unit-tracker.h" + +#include "widgets/spinbutton-events.h" +#include "widgets/spw-utilities.h" +#include "widgets/widget-sizes.h" + +#include "xml/attribute-record.h" +#include "xml/node-event-vector.h" + +#include "ui/toolbar/arc-toolbar.h" +#include "ui/toolbar/box3d-toolbar.h" +#include "ui/toolbar/calligraphy-toolbar.h" +#include "ui/toolbar/connector-toolbar.h" +#include "ui/toolbar/dropper-toolbar.h" +#include "ui/toolbar/eraser-toolbar.h" +#include "ui/toolbar/gradient-toolbar.h" +#include "ui/toolbar/lpe-toolbar.h" +#include "ui/toolbar/mesh-toolbar.h" +#include "ui/toolbar/measure-toolbar.h" +#include "ui/toolbar/node-toolbar.h" +#include "ui/toolbar/rect-toolbar.h" +#include "ui/toolbar/paintbucket-toolbar.h" +#include "ui/toolbar/pencil-toolbar.h" +#include "ui/toolbar/select-toolbar.h" +#include "ui/toolbar/snap-toolbar.h" +#include "ui/toolbar/spray-toolbar.h" +#include "ui/toolbar/spiral-toolbar.h" +#include "ui/toolbar/star-toolbar.h" +#include "ui/toolbar/tweak-toolbar.h" +#include "ui/toolbar/text-toolbar.h" +#include "ui/toolbar/zoom-toolbar.h" + +#include "toolbox.h" + +#include "ui/tools/tool-base.h" + +//#define DEBUG_TEXT + +using Inkscape::UI::UXManager; +using Inkscape::DocumentUndo; +using Inkscape::UI::ToolboxFactory; +using Inkscape::UI::Tools::ToolBase; + +using Inkscape::IO::Resource::get_filename; +using Inkscape::IO::Resource::UIS; + +typedef void (*SetupFunction)(GtkWidget *toolbox, SPDesktop *desktop); +typedef void (*UpdateFunction)(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); + +enum BarId { + BAR_TOOL = 0, + BAR_AUX, + BAR_COMMANDS, + BAR_SNAP, +}; + +#define BAR_ID_KEY "BarIdValue" +#define HANDLE_POS_MARK "x-inkscape-pos" + +GtkIconSize ToolboxFactory::prefToSize( Glib::ustring const &path, int base ) { + static GtkIconSize sizeChoices[] = { + GTK_ICON_SIZE_LARGE_TOOLBAR, + GTK_ICON_SIZE_SMALL_TOOLBAR, + GTK_ICON_SIZE_DND, + GTK_ICON_SIZE_DIALOG + }; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int index = prefs->getIntLimited( path, base, 0, G_N_ELEMENTS(sizeChoices) ); + return sizeChoices[index]; +} + +Gtk::IconSize ToolboxFactory::prefToSize_mm(Glib::ustring const &path, int base) +{ + static Gtk::IconSize sizeChoices[] = { Gtk::ICON_SIZE_LARGE_TOOLBAR, Gtk::ICON_SIZE_SMALL_TOOLBAR, + Gtk::ICON_SIZE_DND, Gtk::ICON_SIZE_DIALOG }; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int index = prefs->getIntLimited(path, base, 0, G_N_ELEMENTS(sizeChoices)); + return sizeChoices[index]; +} + +static struct { + gchar const *type_name; + gchar const *data_name; + sp_verb_t verb; + sp_verb_t doubleclick_verb; +} const tools[] = { + { "/tools/select", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS}, + { "/tools/nodes", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS }, + { "/tools/tweak", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS }, + { "/tools/spray", "spray_tool", SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS }, + { "/tools/zoom", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS }, + { "/tools/measure", "measure_tool", SP_VERB_CONTEXT_MEASURE, SP_VERB_CONTEXT_MEASURE_PREFS }, + { "/tools/shapes/rect", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS }, + { "/tools/shapes/3dbox", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS }, + { "/tools/shapes/arc", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS }, + { "/tools/shapes/star", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS }, + { "/tools/shapes/spiral", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS }, + { "/tools/freehand/pencil", "pencil_tool", SP_VERB_CONTEXT_PENCIL, SP_VERB_CONTEXT_PENCIL_PREFS }, + { "/tools/freehand/pen", "pen_tool", SP_VERB_CONTEXT_PEN, SP_VERB_CONTEXT_PEN_PREFS }, + { "/tools/calligraphic", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS }, + { "/tools/lpetool", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS }, + { "/tools/eraser", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS }, + { "/tools/paintbucket", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS }, + { "/tools/text", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS }, + { "/tools/connector","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS }, + { "/tools/gradient", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS }, + { "/tools/mesh", "mesh_tool", SP_VERB_CONTEXT_MESH, SP_VERB_CONTEXT_MESH_PREFS }, + { "/tools/dropper", "dropper_tool", SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_DROPPER_PREFS }, + { nullptr, nullptr, 0, 0 } +}; + +static struct { + gchar const *type_name; + gchar const *data_name; + GtkWidget *(*create_func)(SPDesktop *desktop); + 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, "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, "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", 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}, + { "/tools/paintbucket", "paintbucket_toolbox", Inkscape::UI::Toolbar::PaintbucketToolbar::create, "PaintbucketToolbar", + SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")}, + { nullptr, nullptr, nullptr, nullptr, + SP_VERB_INVALID, nullptr, nullptr } +}; + + +static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop ); + +static void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop); + +static void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop); +static void update_tool_toolbox(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); + +static void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop); +static void update_aux_toolbox(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); + +static void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop); +static void update_commands_toolbox(SPDesktop *desktop, ToolBase *eventcontext, GtkWidget *toolbox); + +static void trigger_sp_action( GtkAction* /*act*/, gpointer user_data ) +{ + SPAction* targetAction = SP_ACTION(user_data); + if ( targetAction ) { + sp_action_perform( targetAction, nullptr ); + } +} + +static GtkAction* create_action_for_verb( Inkscape::Verb* verb, Inkscape::UI::View::View* view, GtkIconSize size ) +{ + GtkAction* act = nullptr; + + SPAction* targetAction = verb->get_action(Inkscape::ActionContext(view)); + InkAction* inky = ink_action_new( verb->get_id(), _(verb->get_name()), verb->get_tip(), verb->get_image(), size ); + act = GTK_ACTION(inky); + gtk_action_set_sensitive( act, targetAction->sensitive ); + + g_signal_connect( G_OBJECT(inky), "activate", G_CALLBACK(trigger_sp_action), targetAction ); + + // FIXME: memory leak: this is not unrefed anywhere + g_object_ref(G_OBJECT(targetAction)); + g_object_set_data_full(G_OBJECT(inky), "SPAction", (void*) targetAction, (GDestroyNotify) &g_object_unref); + targetAction->signal_set_sensitive.connect( + sigc::bind<0>( + sigc::ptr_fun(>k_action_set_sensitive), + GTK_ACTION(inky))); + + return act; +} + +static std::map<SPDesktop*, Glib::RefPtr<Gtk::ActionGroup> > groups; + +static void desktopDestructHandler(SPDesktop *desktop) +{ + std::map<SPDesktop*, Glib::RefPtr<Gtk::ActionGroup> >::iterator it = groups.find(desktop); + if (it != groups.end()) + { + groups.erase(it); + } +} + +static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* desktop ) +{ + Inkscape::UI::View::View *view = desktop; + gint verbsToUse[] = { + // disabled until we have icons for them: + //find + //SP_VERB_EDIT_TILE, + //SP_VERB_EDIT_UNTILE, + SP_VERB_DIALOG_ALIGN_DISTRIBUTE, + SP_VERB_DIALOG_DISPLAY, + SP_VERB_DIALOG_FILL_STROKE, + SP_VERB_DIALOG_NAMEDVIEW, + SP_VERB_DIALOG_TEXT, + SP_VERB_DIALOG_XML_EDITOR, + SP_VERB_DIALOG_SELECTORS, + SP_VERB_DIALOG_LAYERS, + SP_VERB_EDIT_CLONE, + SP_VERB_EDIT_COPY, + SP_VERB_EDIT_CUT, + SP_VERB_EDIT_DUPLICATE, + SP_VERB_EDIT_PASTE, + SP_VERB_EDIT_REDO, + SP_VERB_EDIT_UNDO, + SP_VERB_EDIT_UNLINK_CLONE, + //SP_VERB_FILE_EXPORT, + SP_VERB_DIALOG_EXPORT, + SP_VERB_FILE_IMPORT, + SP_VERB_FILE_NEW, + SP_VERB_FILE_OPEN, + SP_VERB_FILE_PRINT, + SP_VERB_FILE_SAVE, + SP_VERB_OBJECT_TO_CURVE, + SP_VERB_SELECTION_GROUP, + SP_VERB_SELECTION_OUTLINE, + SP_VERB_SELECTION_UNGROUP, + SP_VERB_ZOOM_1_1, + SP_VERB_ZOOM_1_2, + SP_VERB_ZOOM_2_1, + SP_VERB_ZOOM_DRAWING, + SP_VERB_ZOOM_IN, + SP_VERB_ZOOM_NEXT, + SP_VERB_ZOOM_OUT, + SP_VERB_ZOOM_PAGE, + SP_VERB_ZOOM_PAGE_WIDTH, + SP_VERB_ZOOM_PREV, + SP_VERB_ZOOM_SELECTION, + SP_VERB_ZOOM_CENTER_PAGE + }; + + GtkIconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small"); + Glib::RefPtr<Gtk::ActionGroup> mainActions; + if (desktop == nullptr) + { + return mainActions; + } + + if ( groups.find(desktop) != groups.end() ) { + mainActions = groups[desktop]; + } + + if ( !mainActions ) { + mainActions = Gtk::ActionGroup::create("main"); + groups[desktop] = mainActions; + desktop->connectDestroy(&desktopDestructHandler); + } + + for (int i : verbsToUse) { + Inkscape::Verb* verb = Inkscape::Verb::get(i); + if ( verb ) { + if (!mainActions->get_action(verb->get_id())) { + GtkAction* act = create_action_for_verb( verb, view, toolboxSize ); + mainActions->add(Glib::wrap(act)); + } + } + } + + if ( !mainActions->get_action("ToolZoom") ) { + for ( guint i = 0; i < G_N_ELEMENTS(tools) && tools[i].type_name; i++ ) { + Glib::RefPtr<VerbAction> va = VerbAction::create(Inkscape::Verb::get(tools[i].verb), Inkscape::Verb::get(tools[i].doubleclick_verb), view); + if ( va ) { + mainActions->add(va); + if ( i == 0 ) { + va->set_active(true); + } + } else { + // This creates a blank action using the data_name, this can replace + // tools that have been disabled by compile time options. + Glib::RefPtr<Gtk::Action> act = Gtk::Action::create(Glib::ustring(tools[i].data_name)); + act->set_sensitive(false); + mainActions->add(act); + } + } + } + + return mainActions; +} + + +static GtkWidget* toolboxNewCommon( GtkWidget* tb, BarId id, GtkPositionType /*handlePos*/ ) +{ + g_object_set_data(G_OBJECT(tb), "desktop", nullptr); + + gtk_widget_set_sensitive(tb, FALSE); + + GtkWidget *hb = gtk_event_box_new(); // A simple, neutral container. + gtk_widget_set_name(hb, "ToolboxCommon"); + + gtk_container_add(GTK_CONTAINER(hb), tb); + gtk_widget_show(GTK_WIDGET(tb)); + + sigc::connection* conn = new sigc::connection; + g_object_set_data(G_OBJECT(hb), "event_context_connection", conn); + + gpointer val = GINT_TO_POINTER(id); + g_object_set_data(G_OBJECT(hb), BAR_ID_KEY, val); + + return hb; +} + +GtkWidget *ToolboxFactory::createToolToolbox() +{ + auto tb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_name(tb, "ToolToolbox"); + gtk_box_set_homogeneous(GTK_BOX(tb), FALSE); + + return toolboxNewCommon( tb, BAR_TOOL, GTK_POS_TOP ); +} + +GtkWidget *ToolboxFactory::createAuxToolbox() +{ + auto tb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_name(tb, "AuxToolbox"); + gtk_box_set_homogeneous(GTK_BOX(tb), FALSE); + + return toolboxNewCommon( tb, BAR_AUX, GTK_POS_LEFT ); +} + +//#################################### +//# Commands Bar +//#################################### + +GtkWidget *ToolboxFactory::createCommandsToolbox() +{ + auto tb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_name(tb, "CommandsToolbox"); + gtk_box_set_homogeneous(GTK_BOX(tb), FALSE); + + return toolboxNewCommon( tb, BAR_COMMANDS, GTK_POS_LEFT ); +} + +GtkWidget *ToolboxFactory::createSnapToolbox() +{ + auto tb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_name(tb, "SnapToolbox"); + gtk_box_set_homogeneous(GTK_BOX(tb), FALSE); + + return toolboxNewCommon( tb, BAR_SNAP, GTK_POS_LEFT ); +} + +static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker) +{ + auto adj = Glib::wrap(adjustment, true); + auto inkSpinner = new Inkscape::UI::Widget::SpinButton(adj, climbRate, digits); + inkSpinner->addUnitTracker(unit_tracker); + inkSpinner = Gtk::manage( inkSpinner ); + GtkWidget *widget = GTK_WIDGET( inkSpinner->gobj() ); + return widget; +} + +void ToolboxFactory::setToolboxDesktop(GtkWidget *toolbox, SPDesktop *desktop) +{ + sigc::connection *conn = static_cast<sigc::connection*>(g_object_get_data(G_OBJECT(toolbox), + "event_context_connection")); + + BarId id = static_cast<BarId>( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toolbox), BAR_ID_KEY)) ); + + SetupFunction setup_func = nullptr; + UpdateFunction update_func = nullptr; + + switch (id) { + case BAR_TOOL: + setup_func = setup_tool_toolbox; + update_func = update_tool_toolbox; + break; + + case BAR_AUX: + toolbox = gtk_bin_get_child(GTK_BIN(toolbox)); + setup_func = setup_aux_toolbox; + update_func = update_aux_toolbox; + break; + + case BAR_COMMANDS: + setup_func = setup_commands_toolbox; + update_func = update_commands_toolbox; + break; + + case BAR_SNAP: + setup_func = setup_snap_toolbox; + update_func = updateSnapToolbox; + break; + default: + g_warning("Unexpected toolbox id encountered."); + } + + gpointer ptr = g_object_get_data(G_OBJECT(toolbox), "desktop"); + SPDesktop *old_desktop = static_cast<SPDesktop*>(ptr); + + if (old_desktop) { + std::vector<Gtk::Widget*> children = Glib::wrap(GTK_CONTAINER(toolbox))->get_children(); + for ( auto i:children ) { + gtk_container_remove( GTK_CONTAINER(toolbox), i->gobj() ); + } + } + + g_object_set_data(G_OBJECT(toolbox), "desktop", (gpointer)desktop); + + if (desktop && setup_func && update_func) { + gtk_widget_set_sensitive(toolbox, TRUE); + setup_func(toolbox, desktop); + update_func(desktop, desktop->event_context, toolbox); + *conn = desktop->connectEventContextChanged(sigc::bind (sigc::ptr_fun(update_func), toolbox)); + } else { + gtk_widget_set_sensitive(toolbox, FALSE); + } + +} // end of sp_toolbox_set_desktop() + + +static void setupToolboxCommon( GtkWidget *toolbox, + SPDesktop *desktop, + gchar const *ui_file, + gchar const* toolbarName, + gchar const* sizePref ) +{ + Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop ); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + GtkUIManager* mgr = gtk_ui_manager_new(); + GError* err = nullptr; + + GtkOrientation orientation = GTK_ORIENTATION_HORIZONTAL; + + gtk_ui_manager_insert_action_group( mgr, mainActions->gobj(), 0 ); + + Glib::ustring filename = get_filename(UIS, ui_file); + gtk_ui_manager_add_ui_from_file( mgr, filename.c_str(), &err ); + if(err) { + g_warning("Failed to load %s: %s", filename.c_str(), err->message); + g_error_free(err); + return; + } + + GtkWidget* toolBar = gtk_ui_manager_get_widget( mgr, toolbarName ); + if ( prefs->getBool("/toolbox/icononly", true) ) { + gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS ); + } + + GtkIconSize toolboxSize = ToolboxFactory::prefToSize(sizePref); + gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) ); + + GtkPositionType pos = static_cast<GtkPositionType>(GPOINTER_TO_INT(g_object_get_data( G_OBJECT(toolbox), HANDLE_POS_MARK ))); + orientation = ((pos == GTK_POS_LEFT) || (pos == GTK_POS_RIGHT)) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; + gtk_orientable_set_orientation (GTK_ORIENTABLE(toolBar), orientation); + gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE); + + g_object_set_data(G_OBJECT(toolBar), "desktop", nullptr); + + GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox)); + if ( child ) { + gtk_container_remove( GTK_CONTAINER(toolbox), child ); + } + + gtk_container_add( GTK_CONTAINER(toolbox), toolBar ); +} + +#define noDUMP_DETAILS 1 + +void ToolboxFactory::setOrientation(GtkWidget* toolbox, GtkOrientation orientation) +{ +#if DUMP_DETAILS + g_message("Set orientation for %p to be %d", toolbox, orientation); + GType type = G_OBJECT_TYPE(toolbox); + g_message(" [%s]", g_type_name(type)); + g_message(" %p", g_object_get_data(G_OBJECT(toolbox), BAR_ID_KEY)); +#endif + + GtkPositionType pos = (orientation == GTK_ORIENTATION_HORIZONTAL) ? GTK_POS_LEFT : GTK_POS_TOP; + + if (GTK_IS_BIN(toolbox)) { +#if DUMP_DETAILS + g_message(" is a BIN"); +#endif // DUMP_DETAILS + GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox)); + if (child) { +#if DUMP_DETAILS + GType type2 = G_OBJECT_TYPE(child); + g_message(" child [%s]", g_type_name(type2)); +#endif // DUMP_DETAILS + + if (GTK_IS_BOX(child)) { +#if DUMP_DETAILS + g_message(" is a BOX"); +#endif // DUMP_DETAILS + + std::vector<Gtk::Widget*> children = Glib::wrap(GTK_CONTAINER(child))->get_children(); + if (!children.empty()) { + for (auto curr:children) { + GtkWidget* child2 = curr->gobj(); +#if DUMP_DETAILS + GType type3 = G_OBJECT_TYPE(child2); + g_message(" child2 [%s]", g_type_name(type3)); +#endif // DUMP_DETAILS + + if (GTK_IS_CONTAINER(child2)) { + std::vector<Gtk::Widget*> children2 = Glib::wrap(GTK_CONTAINER(child2))->get_children(); + if (!children2.empty()) { + for (auto curr2:children2) { + GtkWidget* child3 = curr2->gobj(); +#if DUMP_DETAILS + GType type4 = G_OBJECT_TYPE(child3); + g_message(" child3 [%s]", g_type_name(type4)); +#endif // DUMP_DETAILS + if (GTK_IS_TOOLBAR(child3)) { + GtkToolbar* childBar = GTK_TOOLBAR(child3); + gtk_orientable_set_orientation(GTK_ORIENTABLE(childBar), orientation); + } + } + } + } + + + if (GTK_IS_TOOLBAR(child2)) { + GtkToolbar* childBar = GTK_TOOLBAR(child2); + gtk_orientable_set_orientation(GTK_ORIENTABLE(childBar), orientation); + } else { + g_message("need to add dynamic switch"); + } + } + } else { + // The call is being made before the toolbox proper has been setup. + g_object_set_data(G_OBJECT(toolbox), HANDLE_POS_MARK, GINT_TO_POINTER(pos)); + } + } else if (GTK_IS_TOOLBAR(child)) { + GtkToolbar* toolbar = GTK_TOOLBAR(child); + gtk_orientable_set_orientation( GTK_ORIENTABLE(toolbar), orientation ); + } + } + } +} + +void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop) +{ + setupToolboxCommon(toolbox, desktop, "toolbar-tool.ui", "/ui/ToolToolbar", "/toolbox/tools/small"); +} + +void update_tool_toolbox( SPDesktop *desktop, ToolBase *eventcontext, GtkWidget * /*toolbox*/ ) +{ + gchar const *const tname = ( eventcontext + ? eventcontext->getPrefsPath().c_str() //g_type_name(G_OBJECT_TYPE(eventcontext)) + : nullptr ); + Glib::RefPtr<Gtk::ActionGroup> mainActions = create_or_fetch_actions( desktop ); + + for (int i = 0 ; tools[i].type_name ; i++ ) { + Glib::RefPtr<Gtk::Action> act = mainActions->get_action( Inkscape::Verb::get(tools[i].verb)->get_id() ); + if ( act ) { + bool setActive = tname && !strcmp(tname, tools[i].type_name); + Glib::RefPtr<VerbAction> verbAct = Glib::RefPtr<VerbAction>::cast_dynamic(act); + if ( verbAct ) { + verbAct->set_active(setActive); + } + } + } +} + +/** + * \brief Generate the auxiliary toolbox + * + * \details This is the one that appears below the main menu, and contains + * tool-specific toolbars. Each toolbar is created here, using + * its "create" method. + * + * The actual method used for each toolbar is specified in the + * "aux_toolboxes" array, defined above. + */ +void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // Loop through all the toolboxes and create them using either + // their "create" methods. + for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) { + if (aux_toolboxes[i].create_func) { + GtkWidget *sub_toolbox = aux_toolboxes[i].create_func(desktop); + gtk_widget_set_name( sub_toolbox, "SubToolBox" ); + + auto holder = gtk_grid_new(); + gtk_grid_attach(GTK_GRID(holder), sub_toolbox, 0, 0, 1, 1); + + // This part is just for styling + if ( prefs->getBool( "/toolbox/icononly", true) ) { + gtk_toolbar_set_style( GTK_TOOLBAR(sub_toolbox), GTK_TOOLBAR_ICONS ); + } + + GtkIconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small"); + gtk_toolbar_set_icon_size( GTK_TOOLBAR(sub_toolbox), static_cast<GtkIconSize>(toolboxSize) ); + gtk_widget_set_hexpand(sub_toolbox, TRUE); + + // Add a swatch widget if one was specified + if ( aux_toolboxes[i].swatch_verb_id != SP_VERB_INVALID ) { + auto 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); + } + + // Add the new toolbar into the toolbox (i.e., make it the visible toolbar) + // and also store a pointer to it inside the toolbox. This allows the + // active toolbar to be changed. + gtk_container_add(GTK_CONTAINER(toolbox), holder); + gtk_widget_set_name( holder, aux_toolboxes[i].ui_name ); + + // TODO: We could make the toolbox a custom subclass of GtkEventBox + // so that we can store a list of toolbars, rather than using + // GObject data + g_object_set_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name, holder); + gtk_widget_show(sub_toolbox); + gtk_widget_show(holder); + } else if (aux_toolboxes[i].swatch_verb_id != SP_VERB_NONE) { + g_warning("Could not create toolbox %s", aux_toolboxes[i].ui_name); + } + } +} + +void update_aux_toolbox(SPDesktop * /*desktop*/, ToolBase *eventcontext, GtkWidget *toolbox) +{ + gchar const *tname = ( eventcontext + ? eventcontext->getPrefsPath().c_str() //g_type_name(G_OBJECT_TYPE(eventcontext)) + : nullptr ); + for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) { + GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name)); + if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) { + gtk_widget_show_now(sub_toolbox); + g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox); + } else { + gtk_widget_hide(sub_toolbox); + } + //FIX issue #Inkscape686 + GtkAllocation allocation; + gtk_widget_get_allocation(sub_toolbox, &allocation); + gtk_widget_size_allocate(sub_toolbox, &allocation); + } + //FIX issue #Inkscape125 + GtkAllocation allocation; + gtk_widget_get_allocation(toolbox, &allocation); + gtk_widget_size_allocate(toolbox, &allocation); +} + +void setup_commands_toolbox(GtkWidget *toolbox, SPDesktop *desktop) +{ + setupToolboxCommon(toolbox, desktop, "toolbar-commands.ui", "/ui/CommandsToolbar", "/toolbox/small"); +} + +void update_commands_toolbox(SPDesktop * /*desktop*/, ToolBase * /*eventcontext*/, GtkWidget * /*toolbox*/) +{ +} + +void setup_snap_toolbox(GtkWidget *toolbox, SPDesktop *desktop) +{ + Glib::ustring sizePref("/toolbox/secondary"); + auto toolBar = Inkscape::UI::Toolbar::SnapToolbar::create(desktop); + auto prefs = Inkscape::Preferences::get(); + + if ( prefs->getBool("/toolbox/icononly", true) ) { + gtk_toolbar_set_style( GTK_TOOLBAR(toolBar), GTK_TOOLBAR_ICONS ); + } + + GtkIconSize toolboxSize = ToolboxFactory::prefToSize(sizePref.c_str()); + gtk_toolbar_set_icon_size( GTK_TOOLBAR(toolBar), static_cast<GtkIconSize>(toolboxSize) ); + + GtkPositionType pos = static_cast<GtkPositionType>(GPOINTER_TO_INT(g_object_get_data( G_OBJECT(toolbox), HANDLE_POS_MARK ))); + auto orientation = ((pos == GTK_POS_LEFT) || (pos == GTK_POS_RIGHT)) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; + gtk_orientable_set_orientation (GTK_ORIENTABLE(toolBar), orientation); + gtk_toolbar_set_show_arrow(GTK_TOOLBAR(toolBar), TRUE); + + GtkWidget* child = gtk_bin_get_child(GTK_BIN(toolbox)); + if ( child ) { + gtk_container_remove( GTK_CONTAINER(toolbox), child ); + } + + gtk_container_add( GTK_CONTAINER(toolbox), toolBar ); +} + +Glib::ustring ToolboxFactory::getToolboxName(GtkWidget* toolbox) +{ + Glib::ustring name; + BarId id = static_cast<BarId>( GPOINTER_TO_INT(g_object_get_data(G_OBJECT(toolbox), BAR_ID_KEY)) ); + switch(id) { + case BAR_TOOL: + name = "ToolToolbar"; + break; + case BAR_AUX: + name = "AuxToolbar"; + break; + case BAR_COMMANDS: + name = "CommandsToolbar"; + break; + case BAR_SNAP: + name = "SnapToolbar"; + break; + } + + return name; +} + +void ToolboxFactory::updateSnapToolbox(SPDesktop *desktop, ToolBase * /*eventcontext*/, GtkWidget *toolbox) +{ + auto tb = dynamic_cast<Inkscape::UI::Toolbar::SnapToolbar*>(Glib::wrap(GTK_TOOLBAR(gtk_bin_get_child(GTK_BIN(toolbox))))); + + if (!tb) { + std::cerr << "Can't get snap toolbar" << std::endl; + return; + } + + Inkscape::UI::Toolbar::SnapToolbar::update(tb); +} + +void ToolboxFactory::showAuxToolbox(GtkWidget *toolbox_toplevel) +{ + gtk_widget_show(toolbox_toplevel); + GtkWidget *toolbox = gtk_bin_get_child(GTK_BIN(toolbox_toplevel)); + + GtkWidget *shown_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), "shows")); + if (!shown_toolbox) { + return; + } + gtk_widget_show(toolbox); +} + +#define MODE_LABEL_WIDTH 70 + + +/* + 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 : |