summaryrefslogtreecommitdiffstats
path: root/src/ui/toolbar/pencil-toolbar.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:24:48 +0000
commitcca66b9ec4e494c1d919bff0f71a820d8afab1fa (patch)
tree146f39ded1c938019e1ed42d30923c2ac9e86789 /src/ui/toolbar/pencil-toolbar.cpp
parentInitial commit. (diff)
downloadinkscape-upstream/1.2.2.tar.xz
inkscape-upstream/1.2.2.zip
Adding upstream version 1.2.2.upstream/1.2.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/ui/toolbar/pencil-toolbar.cpp692
1 files changed, 692 insertions, 0 deletions
diff --git a/src/ui/toolbar/pencil-toolbar.cpp b/src/ui/toolbar/pencil-toolbar.cpp
new file mode 100644
index 0000000..95de66a
--- /dev/null
+++ b/src/ui/toolbar/pencil-toolbar.cpp
@@ -0,0 +1,692 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/**
+ * @file
+ * Pencil and pen toolbars
+ */
+/* 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 "pencil-toolbar.h"
+
+#include <glibmm/i18n.h>
+#include <gtkmm.h>
+
+#include "desktop.h"
+#include "display/curve.h"
+#include "live_effects/lpe-bendpath.h"
+#include "live_effects/lpe-bspline.h"
+#include "live_effects/lpe-patternalongpath.h"
+#include "live_effects/lpe-powerstroke.h"
+#include "live_effects/lpe-simplify.h"
+#include "live_effects/lpe-spiro.h"
+#include "live_effects/lpeobject-reference.h"
+#include "live_effects/lpeobject.h"
+#include "object/sp-shape.h"
+#include "selection.h"
+#include "ui/icon-names.h"
+#include "ui/tools/freehand-base.h"
+#include "ui/tools/pen-tool.h"
+#include "ui/tools/pencil-tool.h"
+#include "ui/widget/canvas.h"
+#include "ui/widget/combo-tool-item.h"
+#include "ui/widget/label-tool-item.h"
+#include "ui/widget/spin-button-tool-item.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Toolbar {
+PencilToolbar::PencilToolbar(SPDesktop *desktop,
+ bool pencil_mode)
+ : Toolbar(desktop),
+ _tool_is_pencil(pencil_mode)
+{
+ auto prefs = Inkscape::Preferences::get();
+
+ add_freehand_mode_toggle();
+
+ add(* Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ if (_tool_is_pencil) {
+ /* Use pressure */
+ {
+ _pressure_item = add_toggle_button(_("Use pressure input"), _("Use pressure input"));
+ _pressure_item->set_icon_name(INKSCAPE_ICON("draw-use-pressure"));
+ bool pressure = prefs->getBool("/tools/freehand/pencil/pressure", false);
+ _pressure_item->set_active(pressure);
+ _pressure_item->signal_toggled().connect(sigc::mem_fun(*this, &PencilToolbar::use_pencil_pressure));
+ }
+ /* min pressure */
+ {
+ auto minpressure_val = prefs->getDouble("/tools/freehand/pencil/minpressure", 0);
+ _minpressure_adj = Gtk::Adjustment::create(minpressure_val, 0, 100, 1, 0);
+ _minpressure =
+ Gtk::manage(new UI::Widget::SpinButtonToolItem("pencil-minpressure", _("Min:"), _minpressure_adj, 0, 0));
+ _minpressure->set_tooltip_text(_("Min percent of pressure"));
+ _minpressure->set_focus_widget(desktop->canvas);
+ _minpressure_adj->signal_value_changed().connect(
+ sigc::mem_fun(*this, &PencilToolbar::minpressure_value_changed));
+ add(*_minpressure);
+ }
+ /* max pressure */
+ {
+ auto maxpressure_val = prefs->getDouble("/tools/freehand/pencil/maxpressure", 30);
+ _maxpressure_adj = Gtk::Adjustment::create(maxpressure_val, 0, 100, 1, 0);
+ _maxpressure =
+ Gtk::manage(new UI::Widget::SpinButtonToolItem("pencil-maxpressure", _("Max:"), _maxpressure_adj, 0, 0));
+ _maxpressure->set_tooltip_text(_("Max percent of pressure"));
+ _maxpressure->set_focus_widget(desktop->canvas);
+ _maxpressure_adj->signal_value_changed().connect(
+ sigc::mem_fun(*this, &PencilToolbar::maxpressure_value_changed));
+ add(*_maxpressure);
+ }
+
+ /* powerstoke */
+ add_powerstroke_cap();
+
+ add(*Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ /* Tolerance */
+ {
+ std::vector<Glib::ustring> labels = { _("(many nodes, rough)"), _("(default)"), "", "", "", "",
+ _("(few nodes, smooth)") };
+ std::vector<double> values = { 1, 10, 20, 30, 50, 75, 100 };
+ auto tolerance_val = prefs->getDouble("/tools/freehand/pencil/tolerance", 3.0);
+ _tolerance_adj = Gtk::Adjustment::create(tolerance_val, 0, 100.0, 0.5, 1.0);
+ auto tolerance_item =
+ Gtk::manage(new UI::Widget::SpinButtonToolItem("pencil-tolerance", _("Smoothing:"), _tolerance_adj, 1, 2));
+ tolerance_item->set_tooltip_text(_("How much smoothing (simplifying) is applied to the line"));
+ tolerance_item->set_custom_numeric_menu_data(values, labels);
+ tolerance_item->set_focus_widget(desktop->canvas);
+ _tolerance_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PencilToolbar::tolerance_value_changed));
+ add(*tolerance_item);
+ }
+
+ /* LPE simplify based tolerance */
+ {
+ _simplify = add_toggle_button(_("LPE based interactive simplify"), _("LPE based interactive simplify"));
+ _simplify->set_icon_name(INKSCAPE_ICON("interactive_simplify"));
+ _simplify->set_active(prefs->getInt("/tools/freehand/pencil/simplify", 0));
+ _simplify->signal_toggled().connect(sigc::mem_fun(*this, &PencilToolbar::simplify_lpe));
+ }
+
+ /* LPE simplify flatten */
+ {
+ _flatten_simplify = Gtk::manage(new Gtk::ToolButton(_("LPE simplify flatten")));
+ _flatten_simplify->set_tooltip_text(_("LPE simplify flatten"));
+ _flatten_simplify->set_icon_name(INKSCAPE_ICON("flatten"));
+ _flatten_simplify->signal_clicked().connect(sigc::mem_fun(*this, &PencilToolbar::simplify_flatten));
+ add(*_flatten_simplify);
+ }
+
+ add(*Gtk::manage(new Gtk::SeparatorToolItem()));
+ }
+
+ /* advanced shape options */
+ add_advanced_shape_options();
+
+ show_all();
+
+ // Elements must be hidden after show_all() is called
+ guint freehandMode = prefs->getInt(( _tool_is_pencil ?
+ "/tools/freehand/pencil/freehand-mode" :
+ "/tools/freehand/pen/freehand-mode" ), 0);
+ if (freehandMode != 1 && freehandMode != 2) {
+ _flatten_spiro_bspline->set_visible(false);
+ }
+ if (_tool_is_pencil) {
+ use_pencil_pressure();
+ }
+}
+
+GtkWidget *
+PencilToolbar::create_pencil(SPDesktop *desktop)
+{
+ auto toolbar = new PencilToolbar(desktop, true);
+ return GTK_WIDGET(toolbar->gobj());
+}
+
+PencilToolbar::~PencilToolbar()
+{
+ if(_repr) {
+ _repr->removeListenerByData(this);
+ GC::release(_repr);
+ _repr = nullptr;
+ }
+}
+
+void
+PencilToolbar::mode_changed(int mode)
+{
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setInt(freehand_tool_name() + "/freehand-mode", mode);
+
+ if (mode == 1 || mode == 2) {
+ _flatten_spiro_bspline->set_visible(true);
+ } else {
+ _flatten_spiro_bspline->set_visible(false);
+ }
+
+ bool visible = (mode != 2);
+
+ if (_simplify) {
+ _simplify->set_visible(visible);
+ if (_flatten_simplify) {
+ _flatten_simplify->set_visible(visible && _simplify->get_active());
+ }
+ }
+
+ // Recall, the PencilToolbar is also used as the PenToolbar with minor changes.
+ auto *pt = dynamic_cast<Inkscape::UI::Tools::PenTool *>(_desktop->event_context);
+ if (pt) {
+ pt->setPolylineMode();
+ }
+}
+
+/* This is used in generic functions below to share large portions of code between pen and pencil tool */
+Glib::ustring const
+PencilToolbar::freehand_tool_name()
+{
+ return _tool_is_pencil ? "/tools/freehand/pencil" : "/tools/freehand/pen";
+}
+
+void
+PencilToolbar::add_freehand_mode_toggle()
+{
+ auto label = Gtk::manage(new UI::Widget::LabelToolItem(_("Mode:")));
+ label->set_tooltip_text(_("Mode of new lines drawn by this tool"));
+ add(*label);
+ /* Freehand mode toggle buttons */
+ Gtk::RadioToolButton::Group mode_group;
+ auto bezier_mode_btn = Gtk::manage(new Gtk::RadioToolButton(mode_group, _("Bezier")));
+ bezier_mode_btn->set_tooltip_text(_("Create regular Bezier path"));
+ bezier_mode_btn->set_icon_name(INKSCAPE_ICON("path-mode-bezier"));
+ _mode_buttons.push_back(bezier_mode_btn);
+
+ auto spiro_mode_btn = Gtk::manage(new Gtk::RadioToolButton(mode_group, _("Spiro")));
+ spiro_mode_btn->set_tooltip_text(_("Create Spiro path"));
+ spiro_mode_btn->set_icon_name(INKSCAPE_ICON("path-mode-spiro"));
+ _mode_buttons.push_back(spiro_mode_btn);
+
+ auto bspline_mode_btn = Gtk::manage(new Gtk::RadioToolButton(mode_group, _("BSpline")));
+ bspline_mode_btn->set_tooltip_text(_("Create BSpline path"));
+ bspline_mode_btn->set_icon_name(INKSCAPE_ICON("path-mode-bspline"));
+ _mode_buttons.push_back(bspline_mode_btn);
+
+ if (!_tool_is_pencil) {
+ auto zigzag_mode_btn = Gtk::manage(new Gtk::RadioToolButton(mode_group, _("Zigzag")));
+ zigzag_mode_btn->set_tooltip_text(_("Create a sequence of straight line segments"));
+ zigzag_mode_btn->set_icon_name(INKSCAPE_ICON("path-mode-polyline"));
+ _mode_buttons.push_back(zigzag_mode_btn);
+
+ auto paraxial_mode_btn = Gtk::manage(new Gtk::RadioToolButton(mode_group, _("Paraxial")));
+ paraxial_mode_btn->set_tooltip_text(_("Create a sequence of paraxial line segments"));
+ paraxial_mode_btn->set_icon_name(INKSCAPE_ICON("path-mode-polyline-paraxial"));
+ _mode_buttons.push_back(paraxial_mode_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, &PencilToolbar::mode_changed), btn_idx++));
+ }
+
+ auto prefs = Inkscape::Preferences::get();
+
+ add(* Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ /* LPE bspline spiro flatten */
+ _flatten_spiro_bspline = Gtk::manage(new Gtk::ToolButton(_("Flatten Spiro or BSpline LPE")));
+ _flatten_spiro_bspline->set_tooltip_text(_("Flatten Spiro or BSpline LPE"));
+ _flatten_spiro_bspline->set_icon_name(INKSCAPE_ICON("flatten"));
+ _flatten_spiro_bspline->signal_clicked().connect(sigc::mem_fun(*this, &PencilToolbar::flatten_spiro_bspline));
+ add(*_flatten_spiro_bspline);
+
+ guint freehandMode = prefs->getInt(( _tool_is_pencil ?
+ "/tools/freehand/pencil/freehand-mode" :
+ "/tools/freehand/pen/freehand-mode" ), 0);
+ // freehandMode range is (0,5] for the pen tool, (0,3] for the pencil tool
+ // freehandMode = 3 is an old way of signifying pressure, set it to 0.
+ _mode_buttons[(freehandMode < _mode_buttons.size()) ? freehandMode : 0]->set_active();
+}
+
+void
+PencilToolbar::minpressure_value_changed()
+{
+ assert(_tool_is_pencil);
+ // quit if run by the attr_changed listener
+ if (_freeze) {
+ return;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble( "/tools/freehand/pencil/minpressure", _minpressure_adj->get_value());
+}
+
+void
+PencilToolbar::maxpressure_value_changed()
+{
+ assert(_tool_is_pencil);
+ // quit if run by the attr_changed listener
+ if (_freeze) {
+ return;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble( "/tools/freehand/pencil/maxpressure", _maxpressure_adj->get_value());
+}
+
+void
+PencilToolbar::shapewidth_value_changed()
+{
+ // quit if run by the attr_changed listener
+ if (_freeze) {
+ return;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Inkscape::Selection *selection = _desktop->getSelection();
+ SPItem *item = selection->singleItem();
+ SPLPEItem *lpeitem = nullptr;
+ if (item) {
+ lpeitem = dynamic_cast<SPLPEItem *>(item);
+ }
+ using namespace Inkscape::LivePathEffect;
+ double width = _shapescale_adj->get_value();
+ switch (_shape_item->get_active()) {
+ case Inkscape::UI::Tools::TRIANGLE_IN:
+ case Inkscape::UI::Tools::TRIANGLE_OUT:
+ prefs->setDouble("/live_effects/powerstroke/width", width);
+ if (lpeitem) {
+ LPEPowerStroke *effect = dynamic_cast<LPEPowerStroke *>(lpeitem->getFirstPathEffectOfType(POWERSTROKE));
+ if (effect) {
+ std::vector<Geom::Point> points = effect->offset_points.data();
+ if (points.size() == 1) {
+ points[0][Geom::Y] = width;
+ effect->offset_points.param_set_and_write_new_value(points);
+ }
+ }
+ }
+ break;
+ case Inkscape::UI::Tools::ELLIPSE:
+ case Inkscape::UI::Tools::CLIPBOARD:
+ // The scale of the clipboard isn't known, so getting it to the right size isn't possible.
+ prefs->setDouble("/live_effects/skeletal/width", width);
+ if (lpeitem) {
+ LPEPatternAlongPath *effect =
+ dynamic_cast<LPEPatternAlongPath *>(lpeitem->getFirstPathEffectOfType(PATTERN_ALONG_PATH));
+ if (effect) {
+ effect->prop_scale.param_set_value(width);
+ sp_lpe_item_update_patheffect(lpeitem, false, true);
+ }
+ }
+ break;
+ case Inkscape::UI::Tools::BEND_CLIPBOARD:
+ prefs->setDouble("/live_effects/bend_path/width", width);
+ if (lpeitem) {
+ LPEBendPath *effect = dynamic_cast<LPEBendPath *>(lpeitem->getFirstPathEffectOfType(BEND_PATH));
+ if (effect) {
+ effect->prop_scale.param_set_value(width);
+ sp_lpe_item_update_patheffect(lpeitem, false, true);
+ }
+ }
+ break;
+ case Inkscape::UI::Tools::NONE:
+ case Inkscape::UI::Tools::LAST_APPLIED:
+ default:
+ break;
+ }
+}
+
+void
+PencilToolbar::use_pencil_pressure() {
+ assert(_tool_is_pencil);
+ bool pressure = _pressure_item->get_active();
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setBool("/tools/freehand/pencil/pressure", pressure);
+ if (pressure) {
+ _minpressure->set_visible(true);
+ _maxpressure->set_visible(true);
+ _cap_item->set_visible(true);
+ _shape_item->set_visible(false);
+ _shapescale->set_visible(false);
+ _simplify->set_visible(false);
+ _flatten_spiro_bspline->set_visible(false);
+ _flatten_simplify->set_visible(false);
+ for (auto button : _mode_buttons) {
+ button->set_sensitive(false);
+ }
+ } else {
+ guint freehandMode = prefs->getInt("/tools/freehand/pencil/freehand-mode", 0);
+
+ _minpressure->set_visible(false);
+ _maxpressure->set_visible(false);
+ _cap_item->set_visible(false);
+ _shape_item->set_visible(true);
+ _shapescale->set_visible(true);
+ bool simplify_visible = freehandMode != 2;
+ _simplify->set_visible(simplify_visible);
+ _flatten_simplify->set_visible(simplify_visible && _simplify->get_active());
+ if (freehandMode == 1 || freehandMode == 2) {
+ _flatten_spiro_bspline->set_visible(true);
+ }
+ for (auto button : _mode_buttons) {
+ button->set_sensitive(true);
+ }
+ }
+}
+
+void
+PencilToolbar::add_advanced_shape_options()
+{
+ /*advanced shape options */
+ UI::Widget::ComboToolItemColumns columns;
+
+ Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns);
+
+ std::vector<gchar*> freehand_shape_dropdown_items_list = {
+ const_cast<gchar *>(C_("Freehand shape", "None")),
+ _("Triangle in"),
+ _("Triangle out"),
+ _("Ellipse"),
+ _("From clipboard"),
+ _("Bend from clipboard"),
+ _("Last applied")
+ };
+
+ for (auto item:freehand_shape_dropdown_items_list) {
+ Gtk::TreeModel::Row row = *(store->append());
+ row[columns.col_label ] = item;
+ row[columns.col_sensitive] = true;
+ }
+
+ _shape_item = Gtk::manage(UI::Widget::ComboToolItem::create(_("Shape"), _("Shape of new paths drawn by this tool"), "Not Used", store));
+ _shape_item->use_group_label(true);
+
+ auto prefs = Inkscape::Preferences::get();
+ int shape = prefs->getInt((_tool_is_pencil ?
+ "/tools/freehand/pencil/shape" :
+ "/tools/freehand/pen/shape" ), 0);
+ _shape_item->set_active(shape);
+
+ _shape_item->signal_changed().connect(sigc::mem_fun(*this, &PencilToolbar::change_shape));
+ add(*_shape_item);
+
+ /* power width setting */
+ {
+ _shapescale_adj = Gtk::Adjustment::create(2.0, 0.0, 1000.0, 0.5, 1.0);
+ _shapescale =
+ Gtk::manage(new UI::Widget::SpinButtonToolItem("pencil-maxpressure", _("Scale:"), _shapescale_adj, 1, 2));
+ _shapescale->set_tooltip_text(_("Scale of the width of the power stroke shape."));
+ _shapescale->set_focus_widget(_desktop->canvas);
+ _shapescale_adj->signal_value_changed().connect(sigc::mem_fun(*this, &PencilToolbar::shapewidth_value_changed));
+ update_width_value(shape);
+ add(*_shapescale);
+ }
+}
+
+void
+PencilToolbar::change_shape(int shape) {
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setInt(freehand_tool_name() + "/shape", shape);
+ update_width_value(shape);
+}
+
+void
+PencilToolbar::update_width_value(int shape) {
+ /* Update shape width with correct width */
+ auto prefs = Inkscape::Preferences::get();
+ double width = 1.0;
+ _shapescale->set_sensitive(true);
+ double powerstrokedefsize = 10 / (0.265 * _desktop->getDocument()->getDocumentScale()[0] * 2.0);
+ switch (shape) {
+ case Inkscape::UI::Tools::TRIANGLE_IN:
+ case Inkscape::UI::Tools::TRIANGLE_OUT:
+ width = prefs->getDouble("/live_effects/powerstroke/width", powerstrokedefsize);
+ break;
+ case Inkscape::UI::Tools::ELLIPSE:
+ case Inkscape::UI::Tools::CLIPBOARD:
+ width = prefs->getDouble("/live_effects/skeletal/width", 1.0);
+ break;
+ case Inkscape::UI::Tools::BEND_CLIPBOARD:
+ width = prefs->getDouble("/live_effects/bend_path/width", 1.0);
+ break;
+ case Inkscape::UI::Tools::NONE: // Apply width from style?
+ case Inkscape::UI::Tools::LAST_APPLIED:
+ default:
+ _shapescale->set_sensitive(false);
+ break;
+ }
+ _shapescale_adj->set_value(width);
+}
+
+void PencilToolbar::add_powerstroke_cap()
+{
+ /* Powerstroke cap */
+ UI::Widget::ComboToolItemColumns columns;
+
+ Glib::RefPtr<Gtk::ListStore> store = Gtk::ListStore::create(columns);
+
+ std::vector<gchar *> powerstroke_cap_items_list = { const_cast<gchar *>(C_("Cap", "Butt")), _("Square"), _("Round"),
+ _("Peak"), _("Zero width") };
+ for (auto item : powerstroke_cap_items_list) {
+ Gtk::TreeModel::Row row = *(store->append());
+ row[columns.col_label] = item;
+ row[columns.col_sensitive] = true;
+ }
+
+ _cap_item = Gtk::manage(UI::Widget::ComboToolItem::create(_("Caps"), _("Line endings when drawing with pressure-sensitive PowerPencil"), "Not Used", store));
+
+ auto prefs = Inkscape::Preferences::get();
+
+ int cap = prefs->getInt("/live_effects/powerstroke/powerpencilcap", 2);
+ _cap_item->set_active(cap);
+ _cap_item->use_group_label(true);
+
+ _cap_item->signal_changed().connect(sigc::mem_fun(*this, &PencilToolbar::change_cap));
+
+ add(*_cap_item);
+}
+
+void PencilToolbar::change_cap(int cap)
+{
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setInt("/live_effects/powerstroke/powerpencilcap", cap);
+}
+
+void
+PencilToolbar::simplify_lpe()
+{
+ bool simplify = _simplify->get_active();
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setBool(freehand_tool_name() + "/simplify", simplify);
+ _flatten_simplify->set_visible(simplify);
+}
+
+void
+PencilToolbar::simplify_flatten()
+{
+ auto selected = _desktop->getSelection()->items();
+ SPLPEItem* lpeitem = nullptr;
+ for (auto it(selected.begin()); it != selected.end(); ++it){
+ lpeitem = dynamic_cast<SPLPEItem*>(*it);
+ if (lpeitem && lpeitem->hasPathEffect()){
+ PathEffectList lpelist = lpeitem->getEffectList();
+ PathEffectList::iterator i;
+ for (i = lpelist.begin(); i != lpelist.end(); ++i) {
+ LivePathEffectObject *lpeobj = (*i)->lpeobject;
+ if (lpeobj) {
+ Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe();
+ if (dynamic_cast<Inkscape::LivePathEffect::LPESimplify *>(lpe)) {
+ SPShape * shape = dynamic_cast<SPShape *>(lpeitem);
+ if(shape){
+ auto c = SPCurve::copy(shape->curveForEdit());
+ lpe->doEffect(c.get());
+ lpeitem->setCurrentPathEffect(*i);
+ if (lpelist.size() > 1){
+ lpeitem->removeCurrentPathEffect(true);
+ shape->setCurveBeforeLPE(std::move(c));
+ } else {
+ lpeitem->removeCurrentPathEffect(false);
+ shape->setCurve(std::move(c));
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (lpeitem) {
+ _desktop->getSelection()->remove(lpeitem->getRepr());
+ _desktop->getSelection()->add(lpeitem->getRepr());
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ }
+}
+
+void
+PencilToolbar::flatten_spiro_bspline()
+{
+ auto selected = _desktop->getSelection()->items();
+ SPLPEItem* lpeitem = nullptr;
+
+ for (auto it(selected.begin()); it != selected.end(); ++it){
+ lpeitem = dynamic_cast<SPLPEItem*>(*it);
+ if (lpeitem && lpeitem->hasPathEffect()){
+ PathEffectList lpelist = lpeitem->getEffectList();
+ PathEffectList::iterator i;
+ for (i = lpelist.begin(); i != lpelist.end(); ++i) {
+ LivePathEffectObject *lpeobj = (*i)->lpeobject;
+ if (lpeobj) {
+ Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe();
+ if (dynamic_cast<Inkscape::LivePathEffect::LPEBSpline *>(lpe) ||
+ dynamic_cast<Inkscape::LivePathEffect::LPESpiro *>(lpe))
+ {
+ SPShape * shape = dynamic_cast<SPShape *>(lpeitem);
+ if(shape){
+ auto c = SPCurve::copy(shape->curveForEdit());
+ lpe->doEffect(c.get());
+ lpeitem->setCurrentPathEffect(*i);
+ if (lpelist.size() > 1){
+ lpeitem->removeCurrentPathEffect(true);
+ shape->setCurveBeforeLPE(std::move(c));
+ } else {
+ lpeitem->removeCurrentPathEffect(false);
+ shape->setCurve(std::move(c));
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (lpeitem) {
+ _desktop->getSelection()->remove(lpeitem->getRepr());
+ _desktop->getSelection()->add(lpeitem->getRepr());
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ }
+}
+
+GtkWidget *
+PencilToolbar::create_pen(SPDesktop *desktop)
+{
+ auto toolbar = new PencilToolbar(desktop, false);
+ return GTK_WIDGET(toolbar->gobj());
+}
+
+void
+PencilToolbar::tolerance_value_changed()
+{
+ assert(_tool_is_pencil);
+ // quit if run by the attr_changed listener
+ if (_freeze) {
+ return;
+ }
+
+ // in turn, prevent listener from responding
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ _freeze = true;
+ prefs->setDouble("/tools/freehand/pencil/tolerance",
+ _tolerance_adj->get_value());
+ _freeze = false;
+ auto selected = _desktop->getSelection()->items();
+ for (auto it(selected.begin()); it != selected.end(); ++it){
+ SPLPEItem* lpeitem = dynamic_cast<SPLPEItem*>(*it);
+ if (lpeitem && lpeitem->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect *simplify =
+ lpeitem->getFirstPathEffectOfType(Inkscape::LivePathEffect::SIMPLIFY);
+ if(simplify){
+ Inkscape::LivePathEffect::LPESimplify *lpe_simplify = dynamic_cast<Inkscape::LivePathEffect::LPESimplify*>(simplify->getLPEObj()->get_lpe());
+ if (lpe_simplify) {
+ double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0);
+ tol = tol/(100.0*(102.0-tol));
+ std::ostringstream ss;
+ ss << tol;
+ Inkscape::LivePathEffect::Effect *powerstroke =
+ lpeitem->getFirstPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE);
+ bool simplified = false;
+ if(powerstroke){
+ Inkscape::LivePathEffect::LPEPowerStroke *lpe_powerstroke = dynamic_cast<Inkscape::LivePathEffect::LPEPowerStroke*>(powerstroke->getLPEObj()->get_lpe());
+ if(lpe_powerstroke){
+ lpe_powerstroke->getRepr()->setAttribute("is_visible", "false");
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ SPShape *sp_shape = dynamic_cast<SPShape *>(lpeitem);
+ if (sp_shape) {
+ guint previous_curve_length = sp_shape->curve()->get_segment_count();
+ lpe_simplify->getRepr()->setAttribute("threshold", ss.str());
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ simplified = true;
+ guint curve_length = sp_shape->curve()->get_segment_count();
+ std::vector<Geom::Point> ts = lpe_powerstroke->offset_points.data();
+ double factor = (double)curve_length/ (double)previous_curve_length;
+ for (auto & t : ts) {
+ t[Geom::X] = t[Geom::X] * factor;
+ }
+ lpe_powerstroke->offset_points.param_setValue(ts);
+ }
+ lpe_powerstroke->getRepr()->setAttribute("is_visible", "true");
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ }
+ }
+ if(!simplified){
+ lpe_simplify->getRepr()->setAttribute("threshold", ss.str());
+ }
+ }
+ }
+ }
+ }
+}
+
+}
+}
+}
+/*
+ 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 :