summaryrefslogtreecommitdiffstats
path: root/src/selcue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/selcue.cpp')
-rw-r--r--src/selcue.cpp276
1 files changed, 276 insertions, 0 deletions
diff --git a/src/selcue.cpp b/src/selcue.cpp
new file mode 100644
index 0000000..814b187
--- /dev/null
+++ b/src/selcue.cpp
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Helper object for showing selected items
+ *
+ * Authors:
+ * bulia byak <bulia@users.sf.net>
+ * Carl Hetherington <inkscape@carlh.net>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#include "selcue.h"
+
+#include "desktop.h"
+#include "selection.h"
+#include "text-editing.h"
+
+#include "display/control/canvas-item-ctrl.h"
+#include "display/control/canvas-item-rect.h"
+#include "display/control/canvas-item-guideline.h"
+
+#include "libnrtype/Layout-TNG.h"
+
+#include "object/sp-flowtext.h"
+#include "object/sp-text.h"
+
+Inkscape::SelCue::BoundingBoxPrefsObserver::BoundingBoxPrefsObserver(SelCue &sel_cue) :
+ Observer("/tools/bounding_box"),
+ _sel_cue(sel_cue)
+{
+}
+
+void Inkscape::SelCue::BoundingBoxPrefsObserver::notify(Preferences::Entry const &val)
+{
+ _sel_cue._boundingBoxPrefsChanged(static_cast<int>(val.getBool()));
+}
+
+Inkscape::SelCue::SelCue(SPDesktop *desktop)
+ : _desktop(desktop),
+ _bounding_box_prefs_observer(*this)
+{
+ _selection = _desktop->getSelection();
+
+ _sel_changed_connection = _selection->connectChanged(
+ sigc::hide(sigc::mem_fun(*this, &Inkscape::SelCue::_newItemBboxes))
+ );
+
+ {
+ void(SelCue::*modifiedSignal)() = &SelCue::_updateItemBboxes;
+ _sel_modified_connection = _selection->connectModified(
+ sigc::hide(sigc::hide(sigc::mem_fun(*this, modifiedSignal)))
+ );
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ _updateItemBboxes(prefs);
+ prefs->addObserver(_bounding_box_prefs_observer);
+}
+
+Inkscape::SelCue::~SelCue()
+{
+ _sel_changed_connection.disconnect();
+ _sel_modified_connection.disconnect();
+
+ for (auto & item : _item_bboxes) {
+ delete item;
+ }
+ _item_bboxes.clear();
+
+ for (auto & item : _item_lines) {
+ delete item;
+ }
+ _item_lines.clear();
+
+ for (auto & item : _text_baselines) {
+ delete item;
+ }
+ _text_baselines.clear();
+}
+
+void Inkscape::SelCue::_updateItemBboxes()
+{
+ _updateItemBboxes(Inkscape::Preferences::get());
+}
+
+void Inkscape::SelCue::_updateItemBboxes(Inkscape::Preferences *prefs)
+{
+ gint mode = prefs->getInt("/options/selcue/value", MARK);
+ if (mode == NONE) {
+ return;
+ }
+
+ g_return_if_fail(_selection != nullptr);
+
+ int prefs_bbox = prefs->getBool("/tools/bounding_box");
+
+ _updateItemBboxes(mode, prefs_bbox);
+}
+
+void Inkscape::SelCue::_updateItemBboxes(gint mode, int prefs_bbox)
+{
+ auto items = _selection->items();
+ if (_item_bboxes.size() != (unsigned int) boost::distance(items)) {
+ _newItemBboxes();
+ return;
+ }
+
+ int bcount = 0;
+ for (auto item : items) {
+
+ auto canvas_item = _item_bboxes[bcount++];
+
+ if (canvas_item) {
+ Geom::OptRect const b = (prefs_bbox == 0) ?
+ item->desktopVisualBounds() : item->desktopGeometricBounds();
+
+ if (b) {
+ auto ctrl = dynamic_cast<CanvasItemCtrl *>(canvas_item);
+ if (ctrl) {
+ ctrl->set_position(Geom::Point(b->min().x(), b->max().y()));
+ }
+ auto rect = dynamic_cast<CanvasItemRect *>(canvas_item);
+ if (rect) {
+ rect->set_rect(*b);
+ }
+ canvas_item->show();
+ } else { // no bbox
+ canvas_item->hide();
+ }
+ }
+ }
+
+ _newItemLines();
+ _newTextBaselines();
+}
+
+
+void Inkscape::SelCue::_newItemBboxes()
+{
+ for (auto & item : _item_bboxes) {
+ delete item;
+ }
+ _item_bboxes.clear();
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint mode = prefs->getInt("/options/selcue/value", MARK);
+ if (mode == NONE) {
+ return;
+ }
+
+ g_return_if_fail(_selection != nullptr);
+
+ int prefs_bbox = prefs->getBool("/tools/bounding_box");
+
+ auto items = _selection->items();
+ for (auto item : items) {
+
+ Geom::OptRect const bbox = (prefs_bbox == 0) ?
+ item->desktopVisualBounds() : item->desktopGeometricBounds();
+
+ if (bbox) {
+ Inkscape::CanvasItem *canvas_item = nullptr;
+
+ if (mode == MARK) {
+ auto ctrl = new Inkscape::CanvasItemCtrl(_desktop->getCanvasControls(),
+ Inkscape::CANVAS_ITEM_CTRL_TYPE_SHAPER,
+ Geom::Point(bbox->min().x(), bbox->max().y()));
+ ctrl->set_fill(0x000000ff);
+ ctrl->set_stroke(0x0000000ff);
+ canvas_item = ctrl;
+
+ } else if (mode == BBOX) {
+ auto rect = new Inkscape::CanvasItemRect(_desktop->getCanvasControls(), *bbox);
+ rect->set_stroke(0xffffffa0);
+ rect->set_shadow(0x0000c0a0, 1);
+ rect->set_dashed(true);
+ rect->set_inverted(false);
+ canvas_item = rect;
+ }
+
+ if (canvas_item) {
+ canvas_item->set_pickable(false);
+ canvas_item->set_z_position(0); // Just low enough to not get in the way of other draggable knots.
+ canvas_item->show();
+ _item_bboxes.emplace_back(canvas_item);
+ }
+ }
+ }
+
+ _newItemLines();
+ _newTextBaselines();
+}
+
+/**
+ * Create any required visual-only guide lines related to the selection.
+ */
+void Inkscape::SelCue::_newItemLines()
+{
+ for (auto canvas_item : _item_lines) {
+ delete canvas_item;
+ }
+ _item_lines.clear();
+
+ auto bbox = _selection->preferredBounds();
+
+ // Show a set of lines where the anchor is.
+ if (_selection->has_anchor && bbox) {
+ auto anchor = Geom::Scale(_selection->anchor_x, _selection->anchor_y);
+ auto point = bbox->min() + (bbox->dimensions() * anchor);
+ for (bool horz : { false, true }) {
+ auto line = new Inkscape::CanvasItemGuideLine(_desktop->getCanvasGuides(), "", point, Geom::Point(!horz, horz));
+ line->set_z_position(0);
+ line->show();
+ line->set_stroke(0xddddaa11);
+ line->set_inverted(true);
+ _item_lines.emplace_back(line);
+ }
+ }
+}
+
+void Inkscape::SelCue::_newTextBaselines()
+{
+ for (auto canvas_item : _text_baselines) {
+ delete canvas_item;
+ }
+ _text_baselines.clear();
+
+ auto items = _selection->items();
+ for (auto item : items) {
+ std::optional<Geom::Point> pt;
+ if (auto text = dynamic_cast<SPText *>(item)) {
+ pt = text->getBaselinePoint();
+ }
+ if (auto flow = dynamic_cast<SPFlowtext *>(item)) {
+ pt = flow->getBaselinePoint();
+ }
+ if (pt) {
+ auto canvas_item = new Inkscape::CanvasItemCtrl(_desktop->getCanvasControls(),
+ Inkscape::CANVAS_ITEM_CTRL_SHAPE_SQUARE,
+ (*pt) * item->i2dt_affine());
+ canvas_item->set_size(5);
+ canvas_item->set_stroke(0x000000ff);
+ canvas_item->set_fill(0x00000000);
+ canvas_item->set_z_position(0);
+ canvas_item->show();
+ _text_baselines.emplace_back(canvas_item);
+ }
+ }
+}
+
+void Inkscape::SelCue::_boundingBoxPrefsChanged(int prefs_bbox)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint mode = prefs->getInt("/options/selcue/value", MARK);
+ if (mode == NONE) {
+ return;
+ }
+
+ g_return_if_fail(_selection != nullptr);
+
+ _updateItemBboxes(mode, prefs_bbox);
+}
+
+/*
+ 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 :