summaryrefslogtreecommitdiffstats
path: root/src/ui/toolbar/connector-toolbar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/toolbar/connector-toolbar.cpp')
-rw-r--r--src/ui/toolbar/connector-toolbar.cpp431
1 files changed, 431 insertions, 0 deletions
diff --git a/src/ui/toolbar/connector-toolbar.cpp b/src/ui/toolbar/connector-toolbar.cpp
new file mode 100644
index 0000000..305698b
--- /dev/null
+++ b/src/ui/toolbar/connector-toolbar.cpp
@@ -0,0 +1,431 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/**
+ * @file
+ * Connector 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 "connector-toolbar.h"
+
+#include <glibmm/i18n.h>
+
+#include <gtkmm/separatortoolitem.h>
+
+#include "conn-avoid-ref.h"
+
+#include "desktop.h"
+#include "document-undo.h"
+#include "enums.h"
+#include "layer-manager.h"
+#include "selection.h"
+
+#include "object/algorithms/graphlayout.h"
+#include "object/sp-namedview.h"
+#include "object/sp-path.h"
+
+#include "ui/icon-names.h"
+#include "ui/tools/connector-tool.h"
+#include "ui/widget/canvas.h"
+#include "ui/widget/spin-button-tool-item.h"
+
+#include "xml/node-event-vector.h"
+
+using Inkscape::DocumentUndo;
+
+static Inkscape::XML::NodeEventVector connector_tb_repr_events = {
+ nullptr, /* child_added */
+ nullptr, /* child_removed */
+ Inkscape::UI::Toolbar::ConnectorToolbar::event_attr_changed,
+ nullptr, /* content_changed */
+ nullptr /* order_changed */
+};
+
+namespace Inkscape {
+namespace UI {
+namespace Toolbar {
+ConnectorToolbar::ConnectorToolbar(SPDesktop *desktop)
+ : Toolbar(desktop),
+ _freeze(false),
+ _repr(nullptr)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ {
+ auto avoid_item = Gtk::manage(new Gtk::ToolButton(_("Avoid")));
+ avoid_item->set_tooltip_text(_("Make connectors avoid selected objects"));
+ avoid_item->set_icon_name(INKSCAPE_ICON("connector-avoid"));
+ avoid_item->signal_clicked().connect(sigc::mem_fun(*this, &ConnectorToolbar::path_set_avoid));
+ add(*avoid_item);
+ }
+
+ {
+ auto ignore_item = Gtk::manage(new Gtk::ToolButton(_("Ignore")));
+ ignore_item->set_tooltip_text(_("Make connectors ignore selected objects"));
+ ignore_item->set_icon_name(INKSCAPE_ICON("connector-ignore"));
+ ignore_item->signal_clicked().connect(sigc::mem_fun(*this, &ConnectorToolbar::path_set_ignore));
+ add(*ignore_item);
+ }
+
+ // Orthogonal connectors toggle button
+ {
+ _orthogonal = add_toggle_button(_("Orthogonal"),
+ _("Make connector orthogonal or polyline"));
+ _orthogonal->set_icon_name(INKSCAPE_ICON("connector-orthogonal"));
+
+ bool tbuttonstate = prefs->getBool("/tools/connector/orthogonal");
+ _orthogonal->set_active(( tbuttonstate ? TRUE : FALSE ));
+ _orthogonal->signal_toggled().connect(sigc::mem_fun(*this, &ConnectorToolbar::orthogonal_toggled));
+ }
+
+ add(* Gtk::manage(new Gtk::SeparatorToolItem()));
+
+ // Curvature spinbox
+ auto curvature_val = prefs->getDouble("/tools/connector/curvature", defaultConnCurvature);
+ _curvature_adj = Gtk::Adjustment::create(curvature_val, 0, 100, 1.0, 10.0);
+ auto curvature_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("inkscape:connector-curvature", _("Curvature:"), _curvature_adj, 1, 0));
+ curvature_item->set_tooltip_text(_("The amount of connectors curvature"));
+ curvature_item->set_focus_widget(desktop->canvas);
+ _curvature_adj->signal_value_changed().connect(sigc::mem_fun(*this, &ConnectorToolbar::curvature_changed));
+ add(*curvature_item);
+
+ // Spacing spinbox
+ auto spacing_val = prefs->getDouble("/tools/connector/spacing", defaultConnSpacing);
+ _spacing_adj = Gtk::Adjustment::create(spacing_val, 0, 100, 1.0, 10.0);
+ auto spacing_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("inkscape:connector-spacing", _("Spacing:"), _spacing_adj, 1, 0));
+ spacing_item->set_tooltip_text(_("The amount of space left around objects by auto-routing connectors"));
+ spacing_item->set_focus_widget(desktop->canvas);
+ _spacing_adj->signal_value_changed().connect(sigc::mem_fun(*this, &ConnectorToolbar::spacing_changed));
+ add(*spacing_item);
+
+ // Graph (connector network) layout
+ {
+ auto graph_item = Gtk::manage(new Gtk::ToolButton(_("Graph")));
+ graph_item->set_tooltip_text(_("Nicely arrange selected connector network"));
+ graph_item->set_icon_name(INKSCAPE_ICON("distribute-graph"));
+ graph_item->signal_clicked().connect(sigc::mem_fun(*this, &ConnectorToolbar::graph_layout));
+ add(*graph_item);
+ }
+
+ // Default connector length spinbox
+ auto length_val = prefs->getDouble("/tools/connector/length", 100);
+ _length_adj = Gtk::Adjustment::create(length_val, 10, 1000, 10.0, 100.0);
+ auto length_item = Gtk::manage(new UI::Widget::SpinButtonToolItem("inkscape:connector-length", _("Length:"), _length_adj, 1, 0));
+ length_item->set_tooltip_text(_("Ideal length for connectors when layout is applied"));
+ length_item->set_focus_widget(desktop->canvas);
+ _length_adj->signal_value_changed().connect(sigc::mem_fun(*this, &ConnectorToolbar::length_changed));
+ add(*length_item);
+
+ // Directed edges toggle button
+ {
+ _directed_item = add_toggle_button(_("Downwards"),
+ _("Make connectors with end-markers (arrows) point downwards"));
+ _directed_item->set_icon_name(INKSCAPE_ICON("distribute-graph-directed"));
+
+ bool tbuttonstate = prefs->getBool("/tools/connector/directedlayout");
+ _directed_item->set_active(tbuttonstate ? TRUE : FALSE);
+
+ _directed_item->signal_toggled().connect(sigc::mem_fun(*this, &ConnectorToolbar::directed_graph_layout_toggled));
+ desktop->getSelection()->connectChanged(sigc::mem_fun(*this, &ConnectorToolbar::selection_changed));
+ }
+
+ // Avoid overlaps toggle button
+ {
+ _overlap_item = add_toggle_button(_("Remove overlaps"),
+ _("Do not allow overlapping shapes"));
+ _overlap_item->set_icon_name(INKSCAPE_ICON("distribute-remove-overlaps"));
+
+ bool tbuttonstate = prefs->getBool("/tools/connector/avoidoverlaplayout");
+ _overlap_item->set_active(tbuttonstate ? TRUE : FALSE);
+
+ _overlap_item->signal_toggled().connect(sigc::mem_fun(*this, &ConnectorToolbar::nooverlaps_graph_layout_toggled));
+ }
+
+ // Code to watch for changes to the connector-spacing attribute in
+ // the XML.
+ Inkscape::XML::Node *repr = desktop->namedview->getRepr();
+ g_assert(repr != nullptr);
+
+ if(_repr) {
+ _repr->removeListenerByData(this);
+ Inkscape::GC::release(_repr);
+ _repr = nullptr;
+ }
+
+ if (repr) {
+ _repr = repr;
+ Inkscape::GC::anchor(_repr);
+ _repr->addListener(&connector_tb_repr_events, this);
+ _repr->synthesizeEvents(&connector_tb_repr_events, this);
+ }
+
+ show_all();
+}
+
+GtkWidget *
+ConnectorToolbar::create( SPDesktop *desktop)
+{
+ auto toolbar = new ConnectorToolbar(desktop);
+ return GTK_WIDGET(toolbar->gobj());
+} // end of ConnectorToolbar::prep()
+
+void
+ConnectorToolbar::path_set_avoid()
+{
+ Inkscape::UI::Tools::cc_selection_set_avoid(_desktop, true);
+}
+
+void
+ConnectorToolbar::path_set_ignore()
+{
+ Inkscape::UI::Tools::cc_selection_set_avoid(_desktop, false);
+}
+
+void
+ConnectorToolbar::orthogonal_toggled()
+{
+ auto doc = _desktop->getDocument();
+
+ if (!DocumentUndo::getUndoSensitive(doc)) {
+ return;
+ }
+
+ // quit if run by the _changed callbacks
+ if (_freeze) {
+ return;
+ }
+
+ // in turn, prevent callbacks from responding
+ _freeze = true;
+
+ bool is_orthog = _orthogonal->get_active();
+ gchar orthog_str[] = "orthogonal";
+ gchar polyline_str[] = "polyline";
+ gchar *value = is_orthog ? orthog_str : polyline_str ;
+
+ bool modmade = false;
+ auto itemlist= _desktop->getSelection()->items();
+ for(auto i=itemlist.begin();i!=itemlist.end();++i){
+ SPItem *item = *i;
+
+ if (Inkscape::UI::Tools::cc_item_is_connector(item)) {
+ item->setAttribute( "inkscape:connector-type", value);
+ item->getAvoidRef().handleSettingChange();
+ modmade = true;
+ }
+ }
+
+ if (!modmade) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setBool("/tools/connector/orthogonal", is_orthog);
+ } else {
+
+ DocumentUndo::done(doc, is_orthog ? _("Set connector type: orthogonal"): _("Set connector type: polyline"), INKSCAPE_ICON("draw-connector"));
+ }
+
+ _freeze = false;
+}
+
+void
+ConnectorToolbar::curvature_changed()
+{
+ SPDocument *doc = _desktop->getDocument();
+
+ if (!DocumentUndo::getUndoSensitive(doc)) {
+ return;
+ }
+
+
+ // quit if run by the _changed callbacks
+ if (_freeze) {
+ return;
+ }
+
+ // in turn, prevent callbacks from responding
+ _freeze = true;
+
+ auto newValue = _curvature_adj->get_value();
+ gchar value[G_ASCII_DTOSTR_BUF_SIZE];
+ g_ascii_dtostr(value, G_ASCII_DTOSTR_BUF_SIZE, newValue);
+
+ bool modmade = false;
+ auto itemlist= _desktop->getSelection()->items();
+ for(auto i=itemlist.begin();i!=itemlist.end();++i){
+ SPItem *item = *i;
+
+ if (Inkscape::UI::Tools::cc_item_is_connector(item)) {
+ item->setAttribute( "inkscape:connector-curvature", value);
+ item->getAvoidRef().handleSettingChange();
+ modmade = true;
+ }
+ }
+
+ if (!modmade) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble(Glib::ustring("/tools/connector/curvature"), newValue);
+ }
+ else {
+ DocumentUndo::done(doc, _("Change connector curvature"), INKSCAPE_ICON("draw-connector"));
+ }
+
+ _freeze = false;
+}
+
+void
+ConnectorToolbar::spacing_changed()
+{
+ SPDocument *doc = _desktop->getDocument();
+
+ if (!DocumentUndo::getUndoSensitive(doc)) {
+ return;
+ }
+
+ Inkscape::XML::Node *repr = _desktop->namedview->getRepr();
+
+ if ( !repr->attribute("inkscape:connector-spacing") &&
+ ( _spacing_adj->get_value() == defaultConnSpacing )) {
+ // Don't need to update the repr if the attribute doesn't
+ // exist and it is being set to the default value -- as will
+ // happen at startup.
+ return;
+ }
+
+ // quit if run by the attr_changed listener
+ if (_freeze) {
+ return;
+ }
+
+ // in turn, prevent listener from responding
+ _freeze = true;
+
+ repr->setAttributeCssDouble("inkscape:connector-spacing", _spacing_adj->get_value());
+ _desktop->namedview->updateRepr();
+ bool modmade = false;
+
+ std::vector<SPItem *> items;
+ items = get_avoided_items(items, _desktop->layerManager().currentRoot(), _desktop);
+ for (auto item : items) {
+ Geom::Affine m = Geom::identity();
+ avoid_item_move(&m, item);
+ modmade = true;
+ }
+
+ if(modmade) {
+ DocumentUndo::done(doc, _("Change connector spacing"), INKSCAPE_ICON("draw-connector"));
+ }
+ _freeze = false;
+}
+
+void
+ConnectorToolbar::graph_layout()
+{
+ assert(_desktop);
+ if (!_desktop) {
+ return;
+ }
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ // hack for clones, see comment in align-and-distribute.cpp
+ int saved_compensation = prefs->getInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
+ prefs->setInt("/options/clonecompensation/value", SP_CLONE_COMPENSATION_UNMOVED);
+
+ auto tmp = _desktop->getSelection()->items();
+ std::vector<SPItem *> vec(tmp.begin(), tmp.end());
+ graphlayout(vec);
+
+ prefs->setInt("/options/clonecompensation/value", saved_compensation);
+
+ DocumentUndo::done(_desktop->getDocument(), _("Arrange connector network"), INKSCAPE_ICON("dialog-align-and-distribute"));
+}
+
+void
+ConnectorToolbar::length_changed()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble("/tools/connector/length", _length_adj->get_value());
+}
+
+void
+ConnectorToolbar::directed_graph_layout_toggled()
+{
+ auto prefs = Inkscape::Preferences::get();
+ prefs->setBool("/tools/connector/directedlayout", _directed_item->get_active());
+}
+
+void
+ConnectorToolbar::selection_changed(Inkscape::Selection *selection)
+{
+ SPItem *item = selection->singleItem();
+ if (SP_IS_PATH(item))
+ {
+ gdouble curvature = SP_PATH(item)->connEndPair.getCurvature();
+ bool is_orthog = SP_PATH(item)->connEndPair.isOrthogonal();
+ _orthogonal->set_active(is_orthog);
+ _curvature_adj->set_value(curvature);
+ }
+
+}
+
+void
+ConnectorToolbar::nooverlaps_graph_layout_toggled()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setBool("/tools/connector/avoidoverlaplayout",
+ _overlap_item->get_active());
+}
+
+void
+ConnectorToolbar::event_attr_changed(Inkscape::XML::Node *repr,
+ gchar const *name,
+ gchar const * /*old_value*/,
+ gchar const * /*new_value*/,
+ bool /*is_interactive*/,
+ gpointer data)
+{
+ auto toolbar = reinterpret_cast<ConnectorToolbar *>(data);
+
+ if ( !toolbar->_freeze
+ && (strcmp(name, "inkscape:connector-spacing") == 0) ) {
+ gdouble spacing = repr->getAttributeDouble("inkscape:connector-spacing", defaultConnSpacing);
+
+ toolbar->_spacing_adj->set_value(spacing);
+
+ if (toolbar->_desktop->canvas) {
+ toolbar->_desktop->canvas->grab_focus();
+ }
+ }
+}
+
+}
+}
+}
+
+/*
+ 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 :