diff options
Diffstat (limited to 'src/ui/toolbar/lpe-toolbar.cpp')
-rw-r--r-- | src/ui/toolbar/lpe-toolbar.cpp | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/src/ui/toolbar/lpe-toolbar.cpp b/src/ui/toolbar/lpe-toolbar.cpp new file mode 100644 index 0000000..06327ff --- /dev/null +++ b/src/ui/toolbar/lpe-toolbar.cpp @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * @file + * LPE aux toolbar + */ +/* 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> + * + * Copyright (C) 2004 David Turner + * Copyright (C) 2003 MenTaLguY + * Copyright (C) 1999-2011 authors + * Copyright (C) 2001-2002 Ximian, Inc. + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "lpe-toolbar.h" + +#include <gtkmm/radiotoolbutton.h> +#include <gtkmm/separatortoolitem.h> + +#include "live_effects/lpe-line_segment.h" + +#include "ui/dialog/dialog-container.h" +#include "ui/icon-names.h" +#include "ui/tools/lpe-tool.h" +#include "ui/widget/combo-tool-item.h" +#include "ui/widget/unit-tracker.h" + +using Inkscape::UI::Widget::UnitTracker; +using Inkscape::Util::Unit; +using Inkscape::Util::Quantity; +using Inkscape::DocumentUndo; +using Inkscape::UI::Tools::ToolBase; +using Inkscape::UI::Tools::LpeTool; + +namespace Inkscape { +namespace UI { +namespace Toolbar { +LPEToolbar::LPEToolbar(SPDesktop *desktop) + : Toolbar(desktop), + _tracker(new UnitTracker(Util::UNIT_TYPE_LINEAR)), + _freeze(false), + _currentlpe(nullptr), + _currentlpeitem(nullptr) +{ + _tracker->setActiveUnit(_desktop->getNamedView()->display_units); + + auto unit = _tracker->getActiveUnit(); + g_return_if_fail(unit != nullptr); + + auto prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/lpetool/unit", unit->abbr); + + /* Automatically create a list of LPEs that get added to the toolbar **/ + { + Gtk::RadioToolButton::Group mode_group; + + // The first toggle button represents the state that no subtool is active. + auto inactive_mode_btn = Gtk::manage(new Gtk::RadioToolButton(mode_group, _("All inactive"))); + inactive_mode_btn->set_tooltip_text(_("No geometric tool is active")); + inactive_mode_btn->set_icon_name(INKSCAPE_ICON("draw-geometry-inactive")); + _mode_buttons.push_back(inactive_mode_btn); + + Inkscape::LivePathEffect::EffectType type; + for (int i = 1; i < num_subtools; ++i) { // i == 0 ia INVALIDE_LPE. + + type = lpesubtools[i].type; + + auto btn = Gtk::manage(new Gtk::RadioToolButton(mode_group, Inkscape::LivePathEffect::LPETypeConverter.get_label(type))); + btn->set_tooltip_text(_(Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str())); + btn->set_icon_name(lpesubtools[i].icon_name); + _mode_buttons.push_back(btn); + } + + int btn_idx = 0; + for (auto btn : _mode_buttons) { + btn->set_sensitive(true); + add(*btn); + btn->signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &LPEToolbar::mode_changed), btn_idx++)); + } + + int mode = prefs->getInt("/tools/lpetool/mode", 0); + _mode_buttons[mode]->set_active(); + } + + add(* Gtk::manage(new Gtk::SeparatorToolItem())); + + /* Show limiting bounding box */ + { + _show_bbox_item = add_toggle_button(_("Show limiting bounding box"), + _("Show bounding box (used to cut infinite lines)")); + _show_bbox_item->set_icon_name(INKSCAPE_ICON("show-bounding-box")); + _show_bbox_item->signal_toggled().connect(sigc::mem_fun(*this, &LPEToolbar::toggle_show_bbox)); + _show_bbox_item->set_active(prefs->getBool( "/tools/lpetool/show_bbox", true )); + } + + /* Set limiting bounding box to bbox of current selection */ + { + // TODO: Shouldn't this just be a button (not toggle button)? + _bbox_from_selection_item = add_toggle_button(_("Get limiting bounding box from selection"), + _("Set limiting bounding box (used to cut infinite lines) to the bounding box of current selection")); + _bbox_from_selection_item->set_icon_name(INKSCAPE_ICON("draw-geometry-set-bounding-box")); + _bbox_from_selection_item->signal_toggled().connect(sigc::mem_fun(*this, &LPEToolbar::toggle_set_bbox)); + _bbox_from_selection_item->set_active(false); + } + + add(* Gtk::manage(new Gtk::SeparatorToolItem())); + + /* Combo box to choose line segment type */ + { + UI::Widget::ComboToolItemColumns columns; + Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns); + + std::vector<gchar*> line_segment_dropdown_items_list = { + _("Closed"), + _("Open start"), + _("Open end"), + _("Open both") + }; + + for (auto item: line_segment_dropdown_items_list) { + Gtk::TreeModel::Row row = *(store->append()); + row[columns.col_label ] = item; + row[columns.col_sensitive] = true; + } + + _line_segment_combo = Gtk::manage(UI::Widget::ComboToolItem::create(_("Line Type"), _("Choose a line segment type"), "Not Used", store)); + _line_segment_combo->use_group_label(false); + + _line_segment_combo->set_active(0); + + _line_segment_combo->signal_changed().connect(sigc::mem_fun(*this, &LPEToolbar::change_line_segment_type)); + add(*_line_segment_combo); + } + + add(* Gtk::manage(new Gtk::SeparatorToolItem())); + + /* Display measuring info for selected items */ + { + _measuring_item = add_toggle_button(_("Display measuring info"), + _("Display measuring info for selected items")); + _measuring_item->set_icon_name(INKSCAPE_ICON("draw-geometry-show-measuring-info")); + _measuring_item->signal_toggled().connect(sigc::mem_fun(*this, &LPEToolbar::toggle_show_measuring_info)); + _measuring_item->set_active( prefs->getBool( "/tools/lpetool/show_measuring_info", true ) ); + } + + // Add the units menu + { + _units_item = _tracker->create_tool_item(_("Units"), ("") ); + add(*_units_item); + _units_item->signal_changed_after().connect(sigc::mem_fun(*this, &LPEToolbar::unit_changed)); + _units_item->set_sensitive( prefs->getBool("/tools/lpetool/show_measuring_info", true)); + } + + add(* Gtk::manage(new Gtk::SeparatorToolItem())); + + /* Open LPE dialog (to adapt parameters numerically) */ + { + // TODO: Shouldn't this be a regular Gtk::ToolButton (not toggle)? + _open_lpe_dialog_item = add_toggle_button(_("Open LPE dialog"), + _("Open LPE dialog (to adapt parameters numerically)")); + _open_lpe_dialog_item->set_icon_name(INKSCAPE_ICON("dialog-geometry")); + _open_lpe_dialog_item->signal_toggled().connect(sigc::mem_fun(*this, &LPEToolbar::open_lpe_dialog)); + _open_lpe_dialog_item->set_active(false); + } + + desktop->connectEventContextChanged(sigc::mem_fun(*this, &LPEToolbar::watch_ec)); + + show_all(); +} + +void +LPEToolbar::set_mode(int mode) +{ + _mode_buttons[mode]->set_active(); +} + +GtkWidget * +LPEToolbar::create(SPDesktop *desktop) +{ + auto toolbar = new LPEToolbar(desktop); + return GTK_WIDGET(toolbar->gobj()); +} + +// this is called when the mode is changed via the toolbar (i.e., one of the subtool buttons is pressed) +void +LPEToolbar::mode_changed(int mode) +{ + using namespace Inkscape::LivePathEffect; + + ToolBase *ec = _desktop->event_context; + if (!SP_IS_LPETOOL_CONTEXT(ec)) { + return; + } + + // only take action if run by the attr_changed listener + if (!_freeze) { + // in turn, prevent listener from responding + _freeze = true; + + EffectType type = lpesubtools[mode].type; + + LpeTool *lc = SP_LPETOOL_CONTEXT(_desktop->event_context); + bool success = lpetool_try_construction(lc, type); + if (success) { + // since the construction was already performed, we set the state back to inactive + _mode_buttons[0]->set_active(); + mode = 0; + } else { + // switch to the chosen subtool + SP_LPETOOL_CONTEXT(_desktop->event_context)->mode = type; + } + + if (DocumentUndo::getUndoSensitive(_desktop->getDocument())) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt( "/tools/lpetool/mode", mode ); + } + + _freeze = false; + } +} + +void +LPEToolbar::toggle_show_bbox() { + auto prefs = Inkscape::Preferences::get(); + + bool show = _show_bbox_item->get_active(); + prefs->setBool("/tools/lpetool/show_bbox", show); + + LpeTool *lc = dynamic_cast<LpeTool *>(_desktop->event_context); + if (lc) { + lpetool_context_reset_limiting_bbox(lc); + } +} + +void +LPEToolbar::toggle_set_bbox() +{ + auto selection = _desktop->getSelection(); + + auto bbox = selection->visualBounds(); + + if (bbox) { + Geom::Point A(bbox->min()); + Geom::Point B(bbox->max()); + + A *= _desktop->doc2dt(); + B *= _desktop->doc2dt(); + + // TODO: should we provide a way to store points in prefs? + auto prefs = Inkscape::Preferences::get(); + prefs->setDouble("/tools/lpetool/bbox_upperleftx", A[Geom::X]); + prefs->setDouble("/tools/lpetool/bbox_upperlefty", A[Geom::Y]); + prefs->setDouble("/tools/lpetool/bbox_lowerrightx", B[Geom::X]); + prefs->setDouble("/tools/lpetool/bbox_lowerrighty", B[Geom::Y]); + + lpetool_context_reset_limiting_bbox(SP_LPETOOL_CONTEXT(_desktop->event_context)); + } + + _bbox_from_selection_item->set_active(false); +} + +void +LPEToolbar::change_line_segment_type(int mode) +{ + using namespace Inkscape::LivePathEffect; + + // quit if run by the attr_changed listener + if (_freeze) { + return; + } + + // in turn, prevent listener from responding + _freeze = true; + auto line_seg = dynamic_cast<LPELineSegment *>(_currentlpe); + + if (_currentlpeitem && line_seg) { + line_seg->end_type.param_set_value(static_cast<Inkscape::LivePathEffect::EndType>(mode)); + sp_lpe_item_update_patheffect(_currentlpeitem, true, true); + } + + _freeze = false; +} + +void +LPEToolbar::toggle_show_measuring_info() +{ + LpeTool *lc = dynamic_cast<LpeTool *>(_desktop->event_context); + if (!lc) { + return; + } + + bool show = _measuring_item->get_active(); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/lpetool/show_measuring_info", show); + + lpetool_show_measuring_info(lc, show); + + _units_item->set_sensitive( show ); +} + +void +LPEToolbar::unit_changed(int /* NotUsed */) +{ + Unit const *unit = _tracker->getActiveUnit(); + g_return_if_fail(unit != nullptr); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/lpetool/unit", unit->abbr); + + if (SP_IS_LPETOOL_CONTEXT(_desktop->event_context)) { + LpeTool *lc = SP_LPETOOL_CONTEXT(_desktop->event_context); + lpetool_delete_measuring_items(lc); + lpetool_create_measuring_items(lc); + } +} + +void +LPEToolbar::open_lpe_dialog() +{ + if (dynamic_cast<LpeTool *>(_desktop->event_context)) { + _desktop->getContainer()->new_dialog("LivePathEffect"); + } else { + std::cerr << "LPEToolbar::open_lpe_dialog: LPEToolbar active but current tool is not LPE tool!" << std::endl; + } + _open_lpe_dialog_item->set_active(false); +} + +void +LPEToolbar::watch_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolBase* ec) +{ + if (SP_IS_LPETOOL_CONTEXT(ec)) { + // Watch selection + c_selection_modified = desktop->getSelection()->connectModified(sigc::mem_fun(*this, &LPEToolbar::sel_modified)); + c_selection_changed = desktop->getSelection()->connectChanged(sigc::mem_fun(*this, &LPEToolbar::sel_changed)); + sel_changed(desktop->getSelection()); + } else { + if (c_selection_modified) + c_selection_modified.disconnect(); + if (c_selection_changed) + c_selection_changed.disconnect(); + } +} + +void +LPEToolbar::sel_modified(Inkscape::Selection *selection, guint /*flags*/) +{ + ToolBase *ec = selection->desktop()->event_context; + if (SP_IS_LPETOOL_CONTEXT(ec)) { + lpetool_update_measuring_items(SP_LPETOOL_CONTEXT(ec)); + } +} + +void +LPEToolbar::sel_changed(Inkscape::Selection *selection) +{ + using namespace Inkscape::LivePathEffect; + ToolBase *ec = selection->desktop()->event_context; + if (!SP_IS_LPETOOL_CONTEXT(ec)) { + return; + } + LpeTool *lc = SP_LPETOOL_CONTEXT(ec); + + lpetool_delete_measuring_items(lc); + lpetool_create_measuring_items(lc, selection); + + // activate line segment combo box if a single item with LPELineSegment is selected + SPItem *item = selection->singleItem(); + if (item && is<SPLPEItem>(item) && lpetool_item_has_construction(lc, item)) { + + auto lpeitem = cast<SPLPEItem>(item); + Effect* lpe = lpeitem->getCurrentLPE(); + if (lpe && lpe->effectType() == LINE_SEGMENT) { + LPELineSegment *lpels = static_cast<LPELineSegment*>(lpe); + _currentlpe = lpe; + _currentlpeitem = lpeitem; + _line_segment_combo->set_sensitive(true); + _line_segment_combo->set_active( lpels->end_type.get_value() ); + } else { + _currentlpe = nullptr; + _currentlpeitem = nullptr; + _line_segment_combo->set_sensitive(false); + } + + } else { + _currentlpe = nullptr; + _currentlpeitem = nullptr; + _line_segment_combo->set_sensitive(false); + } +} + +} +} +} + +/* + 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 : |