summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2015-11-03 23:23:35 +0000
committerJabiertxof <jtx@jtx.marker.es>2015-11-03 23:23:35 +0000
commitdf701fb4e2c4287cfd503dc255ae3eb9df9c2816 (patch)
tree1849b9c0a513623f8d77a494e0650aca34fc2476 /src
parentpackaging/macosx: revert change included in last commit by mistake (py-report... (diff)
parentFix a bug compiling (diff)
downloadinkscape-df701fb4e2c4287cfd503dc255ae3eb9df9c2816.tar.gz
inkscape-df701fb4e2c4287cfd503dc255ae3eb9df9c2816.zip
Merge of branch lp:~inkscape.dev/inkscape/measure-improvements
(bzr r14444)
Diffstat (limited to 'src')
-rw-r--r--src/document.cpp20
-rw-r--r--src/document.h2
-rw-r--r--src/ui/tools/measure-tool.cpp1444
-rw-r--r--src/ui/tools/measure-tool.h68
-rw-r--r--src/widgets/measure-toolbar.cpp323
-rw-r--r--src/widgets/toolbox.cpp14
6 files changed, 1386 insertions, 485 deletions
diff --git a/src/document.cpp b/src/document.cpp
index c64bf3ed5..0e49f23e2 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -1450,7 +1450,7 @@ std::vector<SPItem*> SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom:
return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps);
}
-std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points) const
+std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers, size_t limit) const
{
std::vector<SPItem*> items;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1464,11 +1464,25 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto
// Cache a flattened SVG DOM to speed up selection.
std::deque<SPItem*> nodes;
build_flat_item_list(&nodes, key, SP_GROUP(this->root), true, false, NULL);
-
+ SPObject *current_layer = SP_ACTIVE_DESKTOP->currentLayer();
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::LayerModel *layer_model = NULL;
+ if(desktop){
+ layer_model = desktop->layers;
+ }
+ size_t item_counter = 0;
for(int i = points.size()-1;i>=0; i--) {
SPItem *item = find_item_at_point(&nodes, key, points[i]);
if (item && items.end()==find(items.begin(),items.end(), item))
- items.push_back(item);
+ if(all_layers || (layer_model && layer_model->layerForObject(item) == current_layer)){
+ items.push_back(item);
+ item_counter++;
+ //limit 0 = no limit
+ if(item_counter == limit){
+ prefs->setDouble("/options/cursortolerance/value", saved_delta);
+ return items;
+ }
+ }
}
// and now we restore it back
diff --git a/src/document.h b/src/document.h
index dd1e295a2..be3f106d8 100644
--- a/src/document.h
+++ b/src/document.h
@@ -262,7 +262,7 @@ public:
std::vector<SPItem*> getItemsInBox(unsigned int dkey, Geom::Rect const &box) const;
std::vector<SPItem*> getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const;
SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const;
- std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points) const;
+ std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers = true, size_t limit = 0) const;
SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const;
void changeUriAndHrefs(char const *uri);
diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp
index 570f3e796..06f32ba5c 100644
--- a/src/ui/tools/measure-tool.cpp
+++ b/src/ui/tools/measure-tool.cpp
@@ -4,6 +4,7 @@
* Authors:
* Felipe Correa da Silva Sanches <juca@members.fsf.org>
* Jon A. Cruz <jon@joncruz.org>
+ * Jabiertxo Arraiza <jabier.arraiza@marker.es>
*
* Copyright (C) 2011 Authors
*
@@ -14,40 +15,57 @@
#include <gdk/gdkkeysyms.h>
#include <boost/none_t.hpp>
#include "util/units.h"
-#include "macros.h"
#include "display/curve.h"
-#include "sp-shape.h"
-#include "sp-text.h"
-#include "sp-flowtext.h"
-#include "text-editing.h"
-#include "display/sp-ctrlline.h"
#include "display/sodipodi-ctrl.h"
+#include "display/sp-ctrlline.h"
+#include "display/sp-canvas.h"
#include "display/sp-canvas-item.h"
#include "display/sp-canvas-util.h"
-#include "desktop.h"
-#include "document.h"
-#include "pixmaps/cursor-measure.xpm"
-#include "preferences.h"
-#include "inkscape.h"
-
+#include "svg/svg.h"
+#include "svg/svg-color.h"
#include "ui/tools/measure-tool.h"
#include "ui/tools/freehand-base.h"
-#include "display/canvas-text.h"
-#include "path-chemistry.h"
-#include "2geom/line.h"
+#include <2geom/line.h>
#include <2geom/path-intersection.h>
#include <2geom/pathvector.h>
#include <2geom/crossing.h>
#include <2geom/angle.h>
-#include "snap.h"
+#include <2geom/transforms.h>
#include "sp-namedview.h"
+#include "sp-shape.h"
+#include "sp-text.h"
+#include "sp-flowtext.h"
+#include "sp-defs.h"
+#include "sp-item.h"
+#include "sp-root.h"
+#include "macros.h"
+#include "svg/stringstream.h"
+#include "rubberband.h"
+#include "path-chemistry.h"
+#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
+#include "viewbox.h"
+#include "snap.h"
+#include "text-editing.h"
+#include "pixmaps/cursor-measure.xpm"
+#include "preferences.h"
+#include "inkscape.h"
+#include "knot.h"
#include "enums.h"
-#include "ui/control-manager.h"
#include "knot-enums.h"
+#include "desktop-style.h"
+#include "verbs.h"
+#include <glibmm/i18n.h>
using Inkscape::ControlManager;
using Inkscape::CTLINE_SECONDARY;
using Inkscape::Util::unit_table;
+using Inkscape::DocumentUndo;
+
+#define MT_KNOT_COLOR_NORMAL 0xffffff00
+#define MT_KNOT_COLOR_MOUSEOVER 0xff000000
+
namespace Inkscape {
namespace UI {
@@ -55,16 +73,14 @@ namespace Tools {
std::vector<Inkscape::Display::TemporaryItem*> measure_tmp_items;
-const std::string& MeasureTool::getPrefsPath() {
- return MeasureTool::prefsPath;
+const std::string& MeasureTool::getPrefsPath()
+{
+ return MeasureTool::prefsPath;
}
const std::string MeasureTool::prefsPath = "/tools/measure";
-namespace
-{
-
-gint const DIMENSION_OFFSET = 35;
+namespace {
/**
* Simple class to use for removing label overlap.
@@ -87,14 +103,16 @@ bool SortLabelPlacement(LabelPlacement const &first, LabelPlacement const &secon
}
}
-void repositionOverlappingLabels(std::vector<LabelPlacement> &placements, SPDesktop *desktop, Geom::Point const &normal, double fontsize)
+//precision is for give the number of decimal positions
+//of the label to calculate label width
+void repositionOverlappingLabels(std::vector<LabelPlacement> &placements, SPDesktop *desktop, Geom::Point const &normal, double fontsize, int precision)
{
std::sort(placements.begin(), placements.end(), SortLabelPlacement);
double border = 3;
Geom::Rect box;
{
- Geom::Point tmp(fontsize * 8 + (border * 2), fontsize + (border * 2));
+ Geom::Point tmp(fontsize * (6 + precision) + (border * 2), fontsize + (border * 2));
tmp = desktop->w2d(tmp);
box = Geom::Rect(-tmp[Geom::X] / 2, -tmp[Geom::Y] / 2, tmp[Geom::X] / 2, tmp[Geom::Y] / 2);
}
@@ -175,6 +193,76 @@ Geom::Point calcAngleDisplayAnchor(SPDesktop *desktop, double angle, double base
}
/**
+ * Create a measure iten in current document.
+ *
+ * @param pathv the path to create.
+ * @param markers, if the path resuts get markers.
+ * @param color of the stroke.
+ * @param measure_repr container element.
+ */
+void setMeasureItem(Geom::PathVector pathv, bool is_curve, bool markers, guint32 color, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ Inkscape::XML::Node *repr;
+ repr = xml_doc->createElement("svg:path");
+ gchar *str = sp_svg_write_path(pathv);
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ Geom::Coord strokewidth = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse().expansionX();
+ std::stringstream stroke_width;
+ stroke_width.imbue(std::locale::classic());
+ if(measure_repr) {
+ stroke_width << strokewidth / desktop->current_zoom();
+ } else {
+ stroke_width << strokewidth;
+ }
+ sp_repr_css_set_property (css, "stroke-width", stroke_width.str().c_str());
+ sp_repr_css_set_property (css, "fill", "none");
+ if(color) {
+ gchar color_line[64];
+ sp_svg_write_color (color_line, sizeof(color_line), color);
+ sp_repr_css_set_property (css, "stroke", color_line);
+ } else {
+ sp_repr_css_set_property (css, "stroke", "#ff0000");
+ }
+ char const * stroke_linecap = is_curve ? "butt" : "square";
+ sp_repr_css_set_property (css, "stroke-linecap", stroke_linecap);
+ sp_repr_css_set_property (css, "stroke-linejoin", "miter");
+ sp_repr_css_set_property (css, "stroke-miterlimit", "4");
+ sp_repr_css_set_property (css, "stroke-dasharray", "none");
+ if(measure_repr) {
+ sp_repr_css_set_property (css, "stroke-opacity", "0.5");
+ } else {
+ sp_repr_css_set_property (css, "stroke-opacity", "1");
+ }
+ if(markers) {
+ sp_repr_css_set_property (css, "marker-start", "url(#Arrow2Sstart)");
+ sp_repr_css_set_property (css, "marker-end", "url(#Arrow2Send)");
+ }
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ repr->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ g_assert( str != NULL );
+ repr->setAttribute("d", str);
+ g_free(str);
+ if(measure_repr) {
+ measure_repr->addChild(repr, NULL);
+ Inkscape::GC::release(repr);
+ } else {
+ SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr));
+ Inkscape::GC::release(repr);
+ item->updateRepr();
+ desktop->getSelection()->clear();
+ desktop->getSelection()->add(item);
+ }
+}
+
+/**
* Given an angle, the arc center and edge point, draw an arc segment centered around that edge point.
*
* @param desktop the desktop that is being used.
@@ -182,8 +270,9 @@ Geom::Point calcAngleDisplayAnchor(SPDesktop *desktop, double angle, double base
* @param end the point that ends at the edge of the arc segment.
* @param anchor the anchor point for displaying the text label.
* @param angle the angle of the arc segment to draw.
+ * @param measure_rpr the container of the curve if converted to items.
*/
-void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom::Point const &end, Geom::Point const &anchor, double angle)
+void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom::Point const &end, Geom::Point const &anchor, double angle, Inkscape::XML::Node *measure_repr = NULL)
{
// Given that we have a point on the arc's edge and the angle of the arc, we need to get the two endpoints.
@@ -191,7 +280,7 @@ void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom
double sideLen = std::abs((end - center).length());
if (sideLen > 0.0) {
double factor = std::min(1.0, textLen / sideLen);
-
+
// arc start
Geom::Point p1 = end * (Geom::Affine(Geom::Translate(-center))
* Geom::Affine(Geom::Scale(factor))
@@ -221,22 +310,186 @@ void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom
SPCtrlCurve *curve = ControlManager::getManager().createControlCurve(desktop->getTempGroup(), p1, p2, p3, p4, CTLINE_SECONDARY);
measure_tmp_items.push_back(desktop->add_temporary_canvasitem(SP_CANVAS_ITEM(curve), 0, true));
+ if(measure_repr) {
+ Geom::PathVector pathv;
+ Geom::Path path;
+ path.start(desktop->doc2dt(p1));
+ path.appendNew<Geom::CubicBezier>(desktop->doc2dt(p2),desktop->doc2dt(p3),desktop->doc2dt(p4));
+ pathv.push_back(path);
+ pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ if(!pathv.empty()) {
+ setMeasureItem(pathv, true, false, 0xff00007f, measure_repr);
+ }
+ }
}
}
} // namespace
-
MeasureTool::MeasureTool()
: ToolBase(cursor_measure_xpm, 4, 4)
, grabbed(NULL)
{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ start_p = readMeasurePoint(true);
+ end_p = readMeasurePoint(false);
+ dimension_offset = 35;
+ // create the knots
+ this->knot_start = new SPKnot(desktop, N_("Measure start"));
+ this->knot_start->setMode(SP_KNOT_MODE_XOR);
+ this->knot_start->setFill(MT_KNOT_COLOR_NORMAL, MT_KNOT_COLOR_MOUSEOVER, MT_KNOT_COLOR_MOUSEOVER);
+ this->knot_start->setStroke(0x0000007f, 0x0000007f, 0x0000007f);
+ this->knot_start->setShape(SP_KNOT_SHAPE_CIRCLE);
+ this->knot_start->updateCtrl();
+ this->knot_end = new SPKnot(desktop, N_("Measure end"));
+ this->knot_end->setMode(SP_KNOT_MODE_XOR);
+ this->knot_end->setFill(MT_KNOT_COLOR_NORMAL, MT_KNOT_COLOR_MOUSEOVER, MT_KNOT_COLOR_MOUSEOVER);
+ this->knot_end->setStroke(0x0000007f, 0x0000007f, 0x0000007f);
+ this->knot_end->setShape(SP_KNOT_SHAPE_CIRCLE);
+ this->knot_end->updateCtrl();
+ Geom::Rect display_area = desktop->get_display_area();
+ if(display_area.interiorContains(start_p) && display_area.interiorContains(end_p) && end_p != Geom::Point()) {
+ this->knot_start->moveto(start_p);
+ this->knot_start->show();
+ this->knot_end->moveto(end_p);
+ this->knot_end->show();
+ showCanvasItems();
+ } else {
+ start_p = Geom::Point(0,0);
+ end_p = Geom::Point(0,0);
+ writeMeasurePoint(start_p, true);
+ writeMeasurePoint(end_p, false);
+ }
+
+ this->_knot_start_moved_connection = this->knot_start->moved_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotStartMovedHandler));
+ this->_knot_start_ungrabbed_connection = this->knot_start->ungrabbed_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotUngrabbedHandler));
+ this->_knot_end_moved_connection = this->knot_end->moved_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotEndMovedHandler));
+ this->_knot_end_ungrabbed_connection = this->knot_end->ungrabbed_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotUngrabbedHandler));
+
}
-MeasureTool::~MeasureTool() {
+MeasureTool::~MeasureTool()
+{
+ this->_knot_start_moved_connection.disconnect();
+ this->_knot_start_ungrabbed_connection.disconnect();
+ this->_knot_end_moved_connection.disconnect();
+ this->_knot_end_ungrabbed_connection.disconnect();
+
+ /* unref should call destroy */
+ knot_unref(this->knot_start);
+ knot_unref(this->knot_end);
+ for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
+ desktop->remove_temporary_canvasitem(measure_tmp_items[idx]);
+ }
+ measure_tmp_items.clear();
}
-void MeasureTool::finish() {
+Geom::Point MeasureTool::readMeasurePoint(bool is_start) {
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return Geom::Point(Geom::infinity(),Geom::infinity());
+ }
+ char const * measure_point = is_start ? "inkscape:measure-start" : "inkscape:measure-end";
+ char const * measure_point_data = namedview->getAttribute (measure_point);
+ if(!measure_point_data) {
+ measure_point_data = "0,0";
+ namedview->setAttribute (measure_point, measure_point_data);
+ }
+ gchar ** strarray = g_strsplit(measure_point_data, ",", 2);
+ double newx, newy;
+ unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
+ success += sp_svg_number_read_d(strarray[1], &newy);
+ g_strfreev (strarray);
+ if (success == 2) {
+ Geom::Point point_data(newx, newy);
+ return point_data;
+ }
+ return Geom::Point(Geom::infinity(),Geom::infinity());
+
+}
+
+void MeasureTool::writeMeasurePoint(Geom::Point point, bool is_start) {
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return;
+ }
+ std::stringstream meassure_point_str;
+ meassure_point_str.imbue(std::locale::classic());
+ meassure_point_str << point[Geom::X] << "," << point[Geom::Y];
+ gchar const *measure_point = is_start ? "inkscape:measure-start" : "inkscape:measure-end";
+ namedview->setAttribute (measure_point, meassure_point_str.str().c_str());
+}
+
+//This function is used to reverse the Measure, I do it in two steps because when move the knot the
+//start_ or the end_p are overwrite so I need the original values.
+void MeasureTool::reverseKnots()
+{
+ Geom::Point start = start_p;
+ Geom::Point end = end_p;
+ this->knot_start->moveto(end);
+ this->knot_start->show();
+ this->knot_end->moveto(start);
+ this->knot_end->show();
+ start_p = end;
+ end_p = start;
+ this->showCanvasItems();
+}
+
+void MeasureTool::knotStartMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state)
+{
+ Geom::Point point = this->knot_start->position();
+ if (state & GDK_CONTROL_MASK) {
+ spdc_endpoint_snap_rotation(this, point, end_p, state);
+ } else if (!(state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(this->knot_end->position());
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ point = sp.getPoint();
+ snap_manager.unSetup();
+ }
+ if(start_p != point) {
+ start_p = point;
+ this->knot_start->moveto(start_p);
+ }
+ showCanvasItems();
+}
+
+void MeasureTool::knotEndMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state)
+{
+ Geom::Point point = this->knot_end->position();
+ if (state & GDK_CONTROL_MASK) {
+ spdc_endpoint_snap_rotation(this, point, start_p, state);
+ } else if (!(state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(this->knot_start->position());
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ point = sp.getPoint();
+ snap_manager.unSetup();
+ }
+ if(end_p != point) {
+ end_p = point;
+ this->knot_end->moveto(end_p);
+ }
+ showCanvasItems();
+}
+
+void MeasureTool::knotUngrabbedHandler(SPKnot */*knot*/, unsigned int state)
+{
+ this->knot_start->moveto(start_p);
+ this->knot_end->moveto(end_p);
+ showCanvasItems();
+}
+
+
+
+void MeasureTool::finish()
+{
this->enableGrDrag(false);
if (this->grabbed) {
@@ -247,498 +500,773 @@ void MeasureTool::finish() {
ToolBase::finish();
}
-//void MeasureTool::setup() {
-// ToolBase* ec = this;
-//
-//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup) {
-//// SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup(ec);
-//// }
-// ToolBase::setup();
-//}
-
-//gint MeasureTool::item_handler(SPItem* item, GdkEvent* event) {
-// gint ret = FALSE;
-//
-//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler) {
-//// ret = SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler(event_context, item, event);
-//// }
-// ret = ToolBase::item_handler(item, event);
-//
-// return ret;
-//}
-
static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom::PathVector const &lineseg, SPCurve *curve, std::vector<double> &intersections)
{
-
curve->transform(item->i2doc_affine());
// Find all intersections of the control-line with this shape
Geom::CrossingSet cs = Geom::crossings(lineseg, curve->get_pathvector());
Geom::delete_duplicates(cs[0]);
// Reconstruct and store the points of intersection
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool only_visible = prefs->getBool("/tools/measure/only_visible", false);
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
for (Geom::Crossings::const_iterator m = cs[0].begin(); m != cs[0].end(); ++m) {
-#if 0
-//TODO: consider only visible intersections
- Geom::Point intersection = lineseg[0].pointAt((*m).ta);
- double eps = 0.0001;
- SPDocument* doc = desktop->getDocument();
- if (((*m).ta > eps &&
- item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta - eps), false, NULL)) ||
+ if(only_visible) {
+ double eps = 0.0001;
+ if (((*m).ta > eps &&
+ item == desktop->getItemAtPoint(desktop->d2w(desktop->dt2doc(lineseg[0].pointAt((*m).ta - eps))), true, NULL)) ||
((*m).ta + eps < 1 &&
- item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta + eps), false, NULL)) ) {
+ item == desktop->getItemAtPoint(desktop->d2w(desktop->dt2doc(lineseg[0].pointAt((*m).ta + eps))), true, NULL))) {
+ intersections.push_back((*m).ta);
+ }
+ } else {
intersections.push_back((*m).ta);
}
-#else
- intersections.push_back((*m).ta);
-
-#endif
}
}
-bool MeasureTool::root_handler(GdkEvent* event) {
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
-
+bool MeasureTool::root_handler(GdkEvent* event)
+{
gint ret = FALSE;
switch (event->type) {
- case GDK_BUTTON_PRESS: {
- Geom::Point const button_w(event->button.x, event->button.y);
- explicitBase = boost::none;
- lastEnd = boost::none;
- start_point = desktop->w2d(button_w);
-
- if (event->button.button == 1 && !this->space_panning) {
- // save drag origin
- xp = static_cast<gint>(event->button.x);
- yp = static_cast<gint>(event->button.y);
- within_tolerance = true;
-
- ret = TRUE;
- }
+ case GDK_BUTTON_PRESS: {
+ this->knot_start->hide();
+ this->knot_end->hide();
+ Geom::Point const button_w(event->button.x, event->button.y);
+ explicitBase = boost::none;
+ last_end = boost::none;
+ start_p = desktop->w2d(button_w);
+
+ if (event->button.button == 1 && !this->space_panning) {
+ // save drag origin
+ start_p = desktop->w2d(Geom::Point(event->button.x, event->button.y));
+ within_tolerance = true;
+
+ ret = TRUE;
+ }
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
- m.freeSnapReturnByRef(start_point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
- m.unSetup();
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ snap_manager.freeSnapReturnByRef(start_p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ snap_manager.unSetup();
- sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
- GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK,
- NULL, event->button.time);
- this->grabbed = SP_CANVAS_ITEM(desktop->acetate);
- break;
- }
- case GDK_KEY_PRESS: {
- if ((event->key.keyval == GDK_KEY_Shift_L) || (event->key.keyval == GDK_KEY_Shift_R)) {
- if (lastEnd) {
- explicitBase = lastEnd;
- }
- }
- break;
+ sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK,
+ NULL, event->button.time);
+ this->grabbed = SP_CANVAS_ITEM(desktop->acetate);
+ break;
+ }
+ case GDK_KEY_PRESS: {
+ if ((event->key.keyval == GDK_KEY_Shift_L) || (event->key.keyval == GDK_KEY_Shift_R)) {
+ explicitBase = end_p;
}
- case GDK_MOTION_NOTIFY: {
- if (!((event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning)) {
- if (!(event->motion.state & GDK_SHIFT_MASK)) {
- Geom::Point const motion_w(event->motion.x, event->motion.y);
- Geom::Point const motion_dt(desktop->w2d(motion_w));
-
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
+ break;
+ }
+ case GDK_MOTION_NOTIFY: {
+ if (!(event->motion.state & GDK_BUTTON1_MASK)) {
+ if(!(event->motion.state & GDK_SHIFT_MASK)) {
+ Geom::Point const motion_w(event->motion.x, event->motion.y);
+ Geom::Point const motion_dt(desktop->w2d(motion_w));
- Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE);
- scp.addOrigin(start_point);
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
- m.preSnap(scp);
- m.unSetup();
- }
- } else {
- ret = TRUE;
+ Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(start_p);
- if ( within_tolerance
- && ( abs( static_cast<gint>(event->motion.x) - xp ) < tolerance )
- && ( abs( static_cast<gint>(event->motion.y) - yp ) < tolerance ) ) {
- break; // do not drag if we're within tolerance from origin
- }
- // Once the user has moved farther than tolerance from the original location
- // (indicating they intend to move the object, not click), then always process the
- // motion notify coordinates as given (no snapping back to origin)
- within_tolerance = false;
-
- //clear previous temporary canvas items, we'll draw new ones
- for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
- desktop->remove_temporary_canvasitem(measure_tmp_items[idx]);
+ snap_manager.preSnap(scp);
+ snap_manager.unSetup();
+ }
+ } else {
+ ret = TRUE;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
+ Geom::Point const motion_w(event->motion.x, event->motion.y);
+ if ( within_tolerance) {
+ if ( Geom::LInfty( motion_w - start_p ) < tolerance) {
+ return FALSE; // Do not drag if we're within tolerance from origin.
}
-
- measure_tmp_items.clear();
-
+ }
+ // Once the user has moved farther than tolerance from the original location
+ // (indicating they intend to move the object, not click), then always process the
+ // motion notify coordinates as given (no snapping back to origin)
+ within_tolerance = false;
+ if(event->motion.time == 0 || !last_end || Geom::LInfty( motion_w - *last_end ) > (tolerance/4.0)) {
Geom::Point const motion_w(event->motion.x, event->motion.y);
Geom::Point const motion_dt(desktop->w2d(motion_w));
- Geom::Point end_point = motion_dt;
+ end_p = motion_dt;
if (event->motion.state & GDK_CONTROL_MASK) {
- spdc_endpoint_snap_rotation(this, end_point, start_point, event->motion.state);
- } else {
- if (!(event->motion.state & GDK_SHIFT_MASK)) {
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
- Inkscape::SnapCandidatePoint scp(end_point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
- scp.addOrigin(start_point);
- Inkscape::SnappedPoint sp = m.freeSnap(scp);
- end_point = sp.getPoint();
- m.unSetup();
- }
- }
-
- Geom::PathVector lineseg;
- Geom::Path p;
- p.start(desktop->dt2doc(start_point));
- p.appendNew<Geom::LineSegment>(desktop->dt2doc(end_point));
- lineseg.push_back(p);
-
- double deltax = end_point[Geom::X] - start_point[Geom::X];
- double deltay = end_point[Geom::Y] - start_point[Geom::Y];
- double angle = atan2(deltay, deltax);
- double baseAngle = 0;
-
- if (explicitBase) {
- double deltax2 = explicitBase.get()[Geom::X] - start_point[Geom::X];
- double deltay2 = explicitBase.get()[Geom::Y] - start_point[Geom::Y];
-
- baseAngle = atan2(deltay2, deltax2);
- angle -= baseAngle;
-
- if (angle < -M_PI) {
- angle += 2 * M_PI;
- } else if (angle > M_PI) {
- angle -= 2 * M_PI;
- }
+ spdc_endpoint_snap_rotation(this, end_p, start_p, event->motion.state);
+ } else if (!(event->motion.state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(end_p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(start_p);
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ end_p = sp.getPoint();
+ snap_manager.unSetup();
}
+ showCanvasItems();
+ last_end = motion_w ;
+ }
+ gobble_motion_events(GDK_BUTTON1_MASK);
+ }
+ break;
+ }
+ case GDK_BUTTON_RELEASE: {
+ this->knot_start->moveto(start_p);
+ this->knot_start->show();
+ if(last_end) {
+ end_p = desktop->w2d(*last_end);
+ if (event->button.state & GDK_CONTROL_MASK) {
+ spdc_endpoint_snap_rotation(this, end_p, start_p, event->motion.state);
+ } else if (!(event->button.state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(end_p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(start_p);
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ end_p = sp.getPoint();
+ snap_manager.unSetup();
+ }
+ }
+ this->knot_end->moveto(end_p);
+ this->knot_end->show();
+ showCanvasItems();
-//TODO: calculate NPOINTS
-//800 seems to be a good value for 800x600 resolution
-#define NPOINTS 800
+ if (this->grabbed) {
+ sp_canvas_item_ungrab(this->grabbed, event->button.time);
+ this->grabbed = NULL;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (!ret) {
+ ret = ToolBase::root_handler(event);
+ }
- std::vector<Geom::Point> points;
+ return ret;
+}
- for (double i = 0; i < NPOINTS; i++) {
- points.push_back(desktop->d2w(start_point + (i / NPOINTS) * (end_point - start_point)));
- }
+void MeasureTool::setMarkers()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *doc = desktop->getDocument();
+ SPObject *arrowStart = doc->getObjectById("Arrow2Sstart");
+ SPObject *arrowEnd = doc->getObjectById("Arrow2Send");
+ if (!arrowStart) {
+ setMarker(true);
+ }
+ if(!arrowEnd) {
+ setMarker(false);
+ }
+}
+void MeasureTool::setMarker(bool isStart)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *doc = desktop->getDocument();
+ SPDefs *defs = doc->getDefs();
+ Inkscape::XML::Node *rmarker;
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ rmarker = xml_doc->createElement("svg:marker");
+ rmarker->setAttribute("id", isStart ? "Arrow2Sstart" : "Arrow2Send");
+ rmarker->setAttribute("inkscape:isstock", "true");
+ rmarker->setAttribute("inkscape:stockid", isStart ? "Arrow2Sstart" : "Arrow2Send");
+ rmarker->setAttribute("orient", "auto");
+ rmarker->setAttribute("refX", "0.0");
+ rmarker->setAttribute("refY", "0.0");
+ rmarker->setAttribute("style", "overflow:visible;");
+ SPItem *marker = SP_ITEM(defs->appendChildRepr(rmarker));
+ Inkscape::GC::release(rmarker);
+ marker->updateRepr();
+ Inkscape::XML::Node *rpath;
+ rpath = xml_doc->createElement("svg:path");
+ rpath->setAttribute("d", "M 8.72,4.03 L -2.21,0.02 L 8.72,-4.00 C 6.97,-1.63 6.98,1.62 8.72,4.03 z");
+ rpath->setAttribute("id", isStart ? "Arrow2SstartPath" : "Arrow2SendPath");
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property (css, "stroke", "none");
+ sp_repr_css_set_property (css, "fill", "#000000");
+ sp_repr_css_set_property (css, "fill-opacity", "1");
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ rpath->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ rpath->setAttribute("transform", isStart ? "scale(0.3) translate(-2.3,0)" : "scale(0.3) rotate(180) translate(-2.3,0)");
+ SPItem *path = SP_ITEM(marker->appendChildRepr(rpath));
+ Inkscape::GC::release(rpath);
+ path->updateRepr();
+}
- // TODO: Felipe, why don't you simply iterate over all items, and test whether their bounding boxes intersect
- // with the measurement line, instead of interpolating over 800 points? E.g. bbox_of_measurement_line.intersects(*bbox_of_item).
- // That's also how the object-snapper works, see _findCandidates() in object-snapper.cpp.
-
- // TODO switch to a different variable name. The single letter 'l' is easy to misread.
-
- //select elements crossed by line segment:
- std::vector<SPItem*> items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points);
- std::vector<double> intersection_times;
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) {
- SPItem *item = *i;
-
- if (SP_IS_SHAPE(item)) {
- calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times);
- } else {
- if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
- Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin();
- do {
- Inkscape::Text::Layout::iterator iter_next = iter;
- iter_next.nextGlyph(); // iter_next is one glyph ahead from iter
- if (iter == iter_next) {
- break;
- }
-
- // get path from iter to iter_next:
- SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next);
- iter = iter_next; // shift to next glyph
- if (!curve) {
- continue; // error converting this glyph
- }
- if (curve->is_empty()) { // whitespace glyph?
- curve->unref();
- continue;
- }
-
- curve->transform(item->i2doc_affine());
-
- calculate_intersections(desktop, item, lineseg, curve, intersection_times);
-
- if (iter == te_get_layout(item)->end()) {
- break;
- }
- } while (true);
- }
- }
- }
+void MeasureTool::toGuides()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ Geom::Point start = desktop->doc2dt(start_p) * desktop->doc2dt();
+ Geom::Point end = desktop->doc2dt(end_p) * desktop->doc2dt();
+ Geom::Ray ray(start,end);
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return;
+ }
+ setGuide(start,ray.angle(), _("Measure"));
+ if(explicitBase) {
+ explicitBase = *explicitBase * SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ ray.setPoints(start, *explicitBase);
+ if(ray.angle() != 0) {
+ setGuide(start,ray.angle(), _("Base"));
+ }
+ }
+ setGuide(start,0,"");
+ setGuide(start,Geom::deg_to_rad(90),_("Start"));
+ setGuide(end,0,_("End"));
+ setGuide(end,Geom::deg_to_rad(90),"");
+ showCanvasItems(true);
+ doc->ensureUpToDate();
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Add guides from measure tool"));
+}
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) {
- intersection_times.push_back(0);
- intersection_times.push_back(1);
- }
+void MeasureTool::toItem()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ Geom::Ray ray(start_p,end_p);
+ guint32 line_color_primary = 0x0000ff7f;
+ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
+ Inkscape::XML::Node *rgroup = xml_doc->createElement("svg:g");
+ showCanvasItems(false, true, rgroup);
+ setLine(start_p,end_p, false, line_color_primary, rgroup);
+ SPItem *measure_item = SP_ITEM(desktop->currentLayer()->appendChildRepr(rgroup));
+ Inkscape::GC::release(rgroup);
+ measure_item->updateRepr();
+ doc->ensureUpToDate();
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Convert measure to items"));
+ reset();
+}
- Glib::ustring unit_name = prefs->getString("/tools/measure/unit");
- if (!unit_name.compare("")) {
- unit_name = "px";
- }
+void MeasureTool::toMarkDimension()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ setMarkers();
+ Geom::Ray ray(start_p,end_p);
+ Geom::Point start = start_p + Geom::Point::polar(ray.angle(), 5);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ dimension_offset = prefs->getDouble("/tools/measure/offset", 5.0);
+ start = start + Geom::Point::polar(ray.angle() + Geom::deg_to_rad(90), -dimension_offset);
+ Geom::Point end = end_p + Geom::Point::polar(ray.angle(), -5);
+ end = end+ Geom::Point::polar(ray.angle() + Geom::deg_to_rad(90), -dimension_offset);
+ guint32 color = 0x000000ff;
+ setLine(start, end, true, color);
+ Glib::ustring unit_name = prefs->getString("/tools/measure/unit");
+ if (!unit_name.compare("")) {
+ unit_name = "px";
+ }
+ double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0);
+ int precision = prefs->getInt("/tools/measure/precision", 2);
+ std::stringstream precision_str;
+ precision_str.imbue(std::locale::classic());
+ precision_str << "%." << precision << "f %s";
+ Geom::Point middle = Geom::middle_point(start, end);
+ double totallengthval = (end_p - start_p).length();
+ totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
+ double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0;
+ gchar *totallength_str = g_strdup_printf(precision_str.str().c_str(), totallengthval * scale, unit_name.c_str());
+ setLabelText(totallength_str, middle, fontsize, Geom::deg_to_rad(180) - ray.angle(), color);
+ g_free(totallength_str);
+ doc->ensureUpToDate();
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Add global measure line"));
+}
- double fontsize = prefs->getInt("/tools/measure/fontsize");
+void MeasureTool::setGuide(Geom::Point origin,double angle, const char *label)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *doc = desktop->getDocument();
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ SPRoot const *root = doc->getRoot();
+ Geom::Affine affine(Geom::identity());
+ if(root) {
+ affine *= root->c2p.inverse();
+ }
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return;
+ }
+ origin *= affine;
+ //measure angle
+ Inkscape::XML::Node *guide;
+ guide = xml_doc->createElement("sodipodi:guide");
+ std::stringstream position;
+ position.imbue(std::locale::classic());
+ position << origin[Geom::X] << "," << origin[Geom::Y];
+ guide->setAttribute("position", position.str().c_str() );
+ guide->setAttribute("inkscape:color", "rgb(167,0,255)");
+ guide->setAttribute("inkscape:label", label);
+ Geom::Point unit_vector = Geom::rot90(origin.polar(angle));
+ std::stringstream angle_str;
+ angle_str.imbue(std::locale::classic());
+ angle_str << unit_vector[Geom::X] << "," << unit_vector[Geom::Y];
+ guide->setAttribute("orientation", angle_str.str().c_str());
+ namedview->appendChild(guide);
+ Inkscape::GC::release(guide);
+}
- // Normal will be used for lines and text
- Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_point - start_point)));
- Geom::Point normal = desktop->w2d(windowNormal);
+void MeasureTool::setLine(Geom::Point start_point,Geom::Point end_point, bool markers, guint32 color, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite()) {
+ return;
+ }
+ Geom::PathVector pathv;
+ Geom::Path path;
+ path.start(desktop->doc2dt(start_point));
+ path.appendNew<Geom::LineSegment>(desktop->doc2dt(end_point));
+ pathv.push_back(path);
+ pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ if(!pathv.empty()) {
+ setMeasureItem(pathv, false, markers, color, measure_repr);
+ }
+}
- std::vector<Geom::Point> intersections;
- std::sort(intersection_times.begin(), intersection_times.end());
- for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); iter_t++) {
- intersections.push_back(lineseg[0].pointAt(*iter_t));
- }
+void MeasureTool::setPoint(Geom::Point origin, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !origin.isFinite()) {
+ return;
+ }
+ char const * svgd;
+ svgd = "m 0.707,0.707 6.586,6.586 m 0,-6.586 -6.586,6.586";
+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
+ Geom::Scale scale = Geom::Scale(desktop->current_zoom()).inverse();
+ pathv *= Geom::Translate(Geom::Point(-3.5,-3.5));
+ pathv *= scale;
+ pathv *= Geom::Translate(Geom::Point() - (scale.vector() * 0.5));
+ pathv *= Geom::Translate(desktop->doc2dt(origin));
+ pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ if (!pathv.empty()) {
+ guint32 line_color_secondary = 0xff0000ff;
+ setMeasureItem(pathv, false, false, line_color_secondary, measure_repr);
+ }
+}
- std::vector<LabelPlacement> placements;
- for (size_t idx = 1; idx < intersections.size(); ++idx) {
- LabelPlacement placement;
- placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length();
- placement.lengthVal = Inkscape::Util::Quantity::convert(placement.lengthVal, "px", unit_name);
- placement.offset = DIMENSION_OFFSET;
- placement.start = desktop->doc2dt( (intersections[idx - 1] + intersections[idx]) / 2 );
- placement.end = placement.start - (normal * placement.offset);
+void MeasureTool::setLabelText(const char *value, Geom::Point pos, double fontsize, Geom::Coord angle, guint32 background, Inkscape::XML::Node *measure_repr, CanvasTextAnchorPositionEnum text_anchor)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
+ /* Create <text> */
+ pos = desktop->doc2dt(pos);
+ Inkscape::XML::Node *rtext = xml_doc->createElement("svg:text");
+ rtext->setAttribute("xml:space", "preserve");
+
+
+ /* Set style */
+ sp_desktop_apply_style_tool(desktop, rtext, "/tools/text", true);
+ if(measure_repr) {
+ sp_repr_set_svg_double(rtext, "x", 2);
+ sp_repr_set_svg_double(rtext, "y", 2);
+ } else {
+ sp_repr_set_svg_double(rtext, "x", 0);
+ sp_repr_set_svg_double(rtext, "y", 0);
+ }
- placements.push_back(placement);
- }
+ /* Create <tspan> */
+ Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan");
+ rtspan->setAttribute("sodipodi:role", "line");
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ std::stringstream font_size;
+ font_size.imbue(std::locale::classic());
+ if(measure_repr) {
+ font_size << fontsize;
+ } else {
+ font_size << fontsize << "pt";
+ }
+ sp_repr_css_set_property (css, "font-size", font_size.str().c_str());
+ sp_repr_css_set_property (css, "font-style", "normal");
+ sp_repr_css_set_property (css, "font-weight", "normal");
+ sp_repr_css_set_property (css, "line-height", "125%");
+ sp_repr_css_set_property (css, "letter-spacing", "0");
+ sp_repr_css_set_property (css, "word-spacing", "0");
+ sp_repr_css_set_property (css, "text-align", "center");
+ sp_repr_css_set_property (css, "text-anchor", "middle");
+ if(measure_repr) {
+ sp_repr_css_set_property (css, "fill", "#FFFFFF");
+ } else {
+ sp_repr_css_set_property (css, "fill", "#000000");
+ }
+ sp_repr_css_set_property (css, "fill-opacity", "1");
+ sp_repr_css_set_property (css, "stroke", "none");
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ rtspan->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ rtext->addChild(rtspan, NULL);
+ Inkscape::GC::release(rtspan);
+ /* Create TEXT */
+ Inkscape::XML::Node *rstring = xml_doc->createTextNode(value);
+ rtspan->addChild(rstring, NULL);
+ Inkscape::GC::release(rstring);
+ SPItem *text_item = SP_ITEM(desktop->currentLayer()->appendChildRepr(rtext));
+ Inkscape::GC::release(rtext);
+ text_item->updateRepr();
+ Geom::OptRect bbox = text_item->geometricBounds();
+ if (!measure_repr && bbox) {
+ Geom::Point center = bbox->midpoint();
+ text_item->transform *= Geom::Translate(center).inverse();
+ pos += Geom::Point::polar(angle+ Geom::deg_to_rad(90), -bbox->height());
+ }
+ if(measure_repr) {
+ /* Create <group> */
+ Inkscape::XML::Node *rgroup = xml_doc->createElement("svg:g");
+ /* Create <rect> */
+ Inkscape::XML::Node *rrect = xml_doc->createElement("svg:rect");
+ SPCSSAttr *css = sp_repr_css_attr_new ();
+ gchar color_line[64];
+ sp_svg_write_color (color_line, sizeof(color_line), background);
+ sp_repr_css_set_property (css, "fill", color_line);
+ sp_repr_css_set_property (css, "fill-opacity", "0.5");
+ sp_repr_css_set_property (css, "stroke-width", "0");
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ rrect->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ sp_repr_set_svg_double(rgroup, "x", 0);
+ sp_repr_set_svg_double(rgroup, "y", 0);
+ sp_repr_set_svg_double(rrect, "x", -bbox->width()/2.0);
+ sp_repr_set_svg_double(rrect, "y", -bbox->height());
+ sp_repr_set_svg_double(rrect, "width", bbox->width() + 6);
+ sp_repr_set_svg_double(rrect, "height", bbox->height() + 6);
+ Inkscape::XML::Node *rtextitem = text_item->getRepr();
+ text_item->deleteObject();
+ rgroup->addChild(rtextitem, NULL);
+ Inkscape::GC::release(rtextitem);
+ rgroup->addChild(rrect, NULL);
+ Inkscape::GC::release(rrect);
+ SPItem *text_item_box = SP_ITEM(desktop->currentLayer()->appendChildRepr(rgroup));
+ Geom::Scale scale = Geom::Scale(desktop->current_zoom()).inverse();
+ if(bbox && text_anchor == TEXT_ANCHOR_CENTER) {
+ text_item_box->transform *= Geom::Translate(bbox->midpoint() - Geom::Point(1.0,1.0)).inverse();
+ }
+ text_item_box->transform *= scale;
+ text_item_box->transform *= Geom::Translate(Geom::Point() - (scale.vector() * 0.5));
+ text_item_box->transform *= Geom::Translate(pos);
+ text_item_box->transform *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ text_item_box->updateRepr();
+ text_item_box->doWriteTransform(text_item_box->getRepr(), text_item_box->transform, NULL, true);
+ Inkscape::XML::Node *rlabel = text_item_box->getRepr();
+ text_item_box->deleteObject();
+ measure_repr->addChild(rlabel, NULL);
+ Inkscape::GC::release(rlabel);
+ } else {
+ text_item->transform *= Geom::Rotate(angle);
+ text_item->transform *= Geom::Translate(pos);
+ text_item->transform *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ text_item->doWriteTransform(text_item->getRepr(), text_item->transform, NULL, true);
+ }
+}
- // Adjust positions
- repositionOverlappingLabels(placements, desktop, windowNormal, fontsize);
-
- for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it)
- {
- LabelPlacement &place = *it;
-
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *measure_str = g_strdup_printf("%.2f %s", place.lengthVal, unit_name.c_str());
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- place.end,
- measure_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x0000007f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(measure_str);
- }
+void MeasureTool::reset()
+{
+ this->knot_start->hide();
+ this->knot_end->hide();
+ for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
+ desktop->remove_temporary_canvasitem(measure_tmp_items[idx]);
+ }
+ measure_tmp_items.clear();
+}
- Geom::Point angleDisplayPt = calcAngleDisplayAnchor(desktop, angle, baseAngle,
- start_point, end_point,
- fontsize);
-
- {
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *angle_str = g_strdup_printf("%.2f °", angle * 180/M_PI);
-
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- angleDisplayPt,
- angle_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x337f337f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(angle_str);
- }
+void MeasureTool::setMeasureCanvasText(bool is_angle, double precision, double amount, double fontsize, Glib::ustring unit_name, Geom::Point position, guint32 background, CanvasTextAnchorPositionEnum text_anchor, bool to_item, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ std::stringstream precision_str;
+ precision_str.imbue(std::locale::classic());
+ if(is_angle){
+ precision_str << "%." << precision << "f °";
+ } else {
+ precision_str << "%." << precision << "f %s";
+ }
+ gchar *measure_str = g_strdup_printf(precision_str.str().c_str(), amount, unit_name.c_str());
+ SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
+ desktop,
+ position,
+ measure_str);
+ sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
+ canvas_tooltip->rgba = 0xffffffff;
+ canvas_tooltip->rgba_background = background;
+ canvas_tooltip->outline = false;
+ canvas_tooltip->background = true;
+ canvas_tooltip->anchor_position = text_anchor;
+ measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
+ if(to_item) {
+ setLabelText(measure_str, position, fontsize, 0, background, measure_repr);
+ }
+ g_free(measure_str);
+}
- {
- double totallengthval = (end_point - start_point).length();
- totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
-
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *totallength_str = g_strdup_printf("%.2f %s", totallengthval, unit_name.c_str());
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- end_point + desktop->w2d(Geom::Point(3*fontsize, -fontsize)),
- totallength_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x3333337f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_LEFT;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(totallength_str);
- }
+void MeasureTool::setMeasureCanvasItem(Geom::Point position, bool to_item, Inkscape::XML::Node *measure_repr){
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(),
+ SP_TYPE_CTRL,
+ "anchor", SP_ANCHOR_CENTER,
+ "size", 8.0,
+ "stroked", TRUE,
+ "stroke_color", 0xff0000ff,
+ "mode", SP_KNOT_MODE_XOR,
+ "shape", SP_KNOT_SHAPE_CROSS,
+ NULL );
+
+ SP_CTRL(canvasitem)->moveto(position);
+ measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0));
+ if(to_item) {
+ setPoint(position, measure_repr);
+ }
+}
- if (intersections.size() > 2) {
- double totallengthval = (intersections[intersections.size()-1] - intersections[0]).length();
- totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
-
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *total_str = g_strdup_printf("%.2f %s", totallengthval, unit_name.c_str());
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- desktop->doc2dt((intersections[0] + intersections[intersections.size()-1])/2) + normal * 60,
- total_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x33337f7f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(total_str);
- }
+void MeasureTool::setMeasureCanvasControlLine(Geom::Point start, Geom::Point end, bool to_item, Inkscape::CtrlLineType ctrl_line_type, Inkscape::XML::Node *measure_repr){
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(),
+ start,
+ end,
+ ctrl_line_type);
+ measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
+ gint32 color = ctrl_line_type == CTLINE_PRIMARY ? 0x0000ff7f : 0xff00007f;
+ if(to_item) {
+ setLine(start,
+ end,
+ false,
+ color,
+ measure_repr);
+ }
+}
- // Now that text has been added, we can add lines and controls so that they go underneath
-
- for (size_t idx = 0; idx < intersections.size(); ++idx) {
- // Display the intersection indicator (i.e. the cross)
- SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(),
- SP_TYPE_CTRL,
- "anchor", SP_ANCHOR_CENTER,
- "size", 8.0,
- "stroked", TRUE,
- "stroke_color", 0xff0000ff,
- "mode", SP_KNOT_MODE_XOR,
- "shape", SP_KNOT_SHAPE_CROSS,
- NULL );
-
- SP_CTRL(canvasitem)->moveto(desktop->doc2dt(intersections[idx]));
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0));
- }
+void MeasureTool::showCanvasItems(bool to_guides, bool to_item, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ writeMeasurePoint(start_p, true);
+ writeMeasurePoint(end_p, false);
+ //clear previous temporary canvas items, we'll draw new ones
+ for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
+ desktop->remove_temporary_canvasitem(measure_tmp_items[idx]);
+ }
+ measure_tmp_items.clear();
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool show_in_between = prefs->getBool("/tools/measure/show_in_between", true);
+ bool all_layers = prefs->getBool("/tools/measure/all_layers", true);
+ dimension_offset = 70;
+ Geom::PathVector lineseg;
+ Geom::Path p;
+ p.start(desktop->dt2doc(start_p));
+ p.appendNew<Geom::LineSegment>(desktop->dt2doc(end_p));
+ lineseg.push_back(p);
+
+ double angle = atan2(end_p - start_p);
+ double baseAngle = 0;
+
+ if (explicitBase) {
+ baseAngle = atan2(explicitBase.get() - start_p);
+ angle -= baseAngle;
+ }
- // Since adding goes to the bottom, do all lines last.
-
- // draw main control line
- {
- SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(),
- start_point,
- end_point);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
-
- if ((end_point[Geom::X] != start_point[Geom::X]) && (end_point[Geom::Y] != start_point[Geom::Y])) {
- double length = std::abs((end_point - start_point).length());
- Geom::Point anchorEnd = start_point;
- anchorEnd[Geom::X] += length;
- if (explicitBase) {
- anchorEnd *= (Geom::Affine(Geom::Translate(-start_point))
- * Geom::Affine(Geom::Rotate(baseAngle))
- * Geom::Affine(Geom::Translate(start_point)));
- }
-
- SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(),
- start_point,
- anchorEnd,
- CTLINE_SECONDARY);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
-
- createAngleDisplayCurve(desktop, start_point, end_point, angleDisplayPt, angle);
+ std::vector<SPItem*> items;
+ Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
+ r->setMode(RUBBERBAND_MODE_TOUCHPATH);
+ if(!show_in_between) {
+ r->start(desktop,start_p);
+ r->move(end_p);
+ items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints(), all_layers, 2);
+ r->stop();
+ r->setMode(RUBBERBAND_MODE_TOUCHPATH);
+ r->start(desktop,end_p);
+ r->move(start_p);
+ std::vector<SPItem*> items_reverse = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints(), all_layers, 2);
+ r->stop();
+ if(items_reverse.size() == 2 && items_reverse[1] != items[0] && items_reverse[1] != items[1]) {
+ items.push_back(items_reverse[1]);
+ }
+ if(items_reverse.size() >= 1 && items_reverse[0] != items[1]) {
+ items.push_back(items_reverse[0]);
+ }
+ } else {
+ r->start(desktop,start_p);
+ r->move(end_p);
+ items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints(), all_layers);
+ r->stop();
+ }
+ std::vector<double> intersection_times;
+ for (std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end(); i++) {
+ SPItem *item = *i;
+ if (SP_IS_SHAPE(item)) {
+ calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times);
+ } else {
+ if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
+ Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin();
+ do {
+ Inkscape::Text::Layout::iterator iter_next = iter;
+ iter_next.nextGlyph(); // iter_next is one glyph ahead from iter
+ if (iter == iter_next) {
+ break;
}
- }
-
- if (intersections.size() > 2) {
- ControlManager &mgr = ControlManager::getManager();
- SPCtrlLine *control_line = 0;
- control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(intersections[0]) + normal * 60,
- desktop->doc2dt(intersections[intersections.size() - 1]) + normal * 60);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
-
- control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(intersections[0]),
- desktop->doc2dt(intersections[0]) + normal * 65);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
-
- control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(intersections[intersections.size() - 1]),
- desktop->doc2dt(intersections[intersections.size() - 1]) + normal * 65);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
- }
- // call-out lines
- for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it)
- {
- LabelPlacement &place = *it;
-
- ControlManager &mgr = ControlManager::getManager();
- SPCtrlLine *control_line = mgr.createControlLine(desktop->getTempGroup(),
- place.start,
- place.end,
- CTLINE_SECONDARY);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
- }
+ // get path from iter to iter_next:
+ SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next);
+ iter = iter_next; // shift to next glyph
+ if (!curve) {
+ continue; // error converting this glyph
+ }
+ if (curve->is_empty()) { // whitespace glyph?
+ curve->unref();
+ continue;
+ }
- {
- for (size_t idx = 1; idx < intersections.size(); ++idx) {
- Geom::Point measure_text_pos = (intersections[idx - 1] + intersections[idx]) / 2;
+ curve->transform(item->i2doc_affine());
- ControlManager &mgr = ControlManager::getManager();
- SPCtrlLine *control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(measure_text_pos),
- desktop->doc2dt(measure_text_pos) - (normal * DIMENSION_OFFSET),
- CTLINE_SECONDARY);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
+ calculate_intersections(desktop, item, lineseg, curve, intersection_times);
+ if (iter == te_get_layout(item)->end()) {
+ break;
}
- }
+ } while (true);
+ }
+ }
+ }
+ Glib::ustring unit_name = prefs->getString("/tools/measure/unit");
+ if (!unit_name.compare("")) {
+ unit_name = "px";
+ }
+ double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0;
+ double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0);
+ // Normal will be used for lines and text
+ Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_p - start_p)));
+ Geom::Point normal = desktop->w2d(windowNormal);
+
+ std::vector<Geom::Point> intersections;
+ std::sort(intersection_times.begin(), intersection_times.end());
+ for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); iter_t++) {
+ if(show_in_between) {
+ intersections.push_back(lineseg[0].pointAt(*iter_t));
+ }
+ }
+ if(!show_in_between && intersection_times.size() > 1) {
+ intersections.push_back(lineseg[0].pointAt(intersection_times[0]));
+ intersections.push_back(lineseg[0].pointAt(intersection_times[intersection_times.size()-1]));
+ }
+ if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) {
+ intersections.insert(intersections.begin(),lineseg[0].pointAt(0));
+ intersections.push_back(lineseg[0].pointAt(1));
+ }
+ std::vector<LabelPlacement> placements;
+ for (size_t idx = 1; idx < intersections.size(); ++idx) {
+ LabelPlacement placement;
+ placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length();
+ placement.lengthVal = Inkscape::Util::Quantity::convert(placement.lengthVal, "px", unit_name);
+ placement.offset = dimension_offset / 2;
+ placement.start = desktop->doc2dt( (intersections[idx - 1] + intersections[idx]) / 2 );
+ placement.end = placement.start - (normal * placement.offset);
+
+ placements.push_back(placement);
+ }
+ int precision = prefs->getInt("/tools/measure/precision", 2);
+ // Adjust positions
+ repositionOverlappingLabels(placements, desktop, windowNormal, fontsize, precision);
+ for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) {
+ LabelPlacement &place = *it;
+ setMeasureCanvasText(false, precision, place.lengthVal * scale, fontsize, unit_name, place.end, 0x0000007f, TEXT_ANCHOR_CENTER, to_item, measure_repr);
+ }
+ Geom::Point angleDisplayPt = calcAngleDisplayAnchor(desktop, angle, baseAngle,
+ start_p, end_p,
+ fontsize);
+ {
+ setMeasureCanvasText(true, precision, Geom::rad_to_deg(angle), fontsize, unit_name, angleDisplayPt, 0x337f337f, TEXT_ANCHOR_CENTER, to_item, measure_repr);
+ }
- // Initial point
- {
- SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(),
- SP_TYPE_CTRL,
- "anchor", SP_ANCHOR_CENTER,
- "size", 8.0,
- "stroked", TRUE,
- "stroke_color", 0xff0000ff,
- "mode", SP_KNOT_MODE_XOR,
- "shape", SP_KNOT_SHAPE_CROSS,
- NULL );
-
- SP_CTRL(canvasitem)->moveto(start_point);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0));
- }
+ {
+ double totallengthval = (end_p - start_p).length();
+ totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
+ Geom::Point origin = end_p + desktop->w2d(Geom::Point(3*fontsize, -fontsize));
+ setMeasureCanvasText(false, precision, totallengthval * scale, fontsize, unit_name, origin, 0x3333337f, TEXT_ANCHOR_LEFT, to_item, measure_repr);
+ }
- lastEnd = end_point; // track in case we get a anchoring key-press later
+ if (intersections.size() > 2) {
+ double totallengthval = (intersections[intersections.size()-1] - intersections[0]).length();
+ totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
+ Geom::Point origin = desktop->doc2dt((intersections[0] + intersections[intersections.size()-1])/2) + normal * dimension_offset;
+ setMeasureCanvasText(false, precision, totallengthval * scale, fontsize, unit_name, origin, 0x33337f7f, TEXT_ANCHOR_CENTER, to_item, measure_repr);
+ }
+
+ // Initial point
+ {
+ setMeasureCanvasItem(start_p, false, measure_repr);
+ }
- gobble_motion_events(GDK_BUTTON1_MASK);
+ // Now that text has been added, we can add lines and controls so that they go underneath
+ for (size_t idx = 0; idx < intersections.size(); ++idx) {
+ setMeasureCanvasItem(desktop->doc2dt(intersections[idx]), to_item, measure_repr);
+ if(to_guides) {
+ gchar *cross_number;
+ if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) {
+ cross_number= g_strdup_printf(_("Crossing %d"), idx);
+ } else {
+ cross_number= g_strdup_printf(_("Crossing %d"), idx + 1);
}
- break;
- }
- case GDK_BUTTON_RELEASE: {
- sp_event_context_discard_delayed_snap_event(this);
- explicitBase = boost::none;
- lastEnd = boost::none;
-
- //clear all temporary canvas items related to the measurement tool.
- for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
- desktop->remove_temporary_canvasitem(measure_tmp_items[idx]);
+ if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true) && idx == 0) {
+ setGuide(desktop->doc2dt(intersections[idx]), angle + Geom::deg_to_rad(90), "");
+ } else {
+ setGuide(desktop->doc2dt(intersections[idx]), angle + Geom::deg_to_rad(90), cross_number);
}
+ g_free(cross_number);
+ }
+ }
+ // Since adding goes to the bottom, do all lines last.
- measure_tmp_items.clear();
+ // draw main control line
+ {
+ setMeasureCanvasControlLine(start_p, end_p, false, CTLINE_PRIMARY, measure_repr);
+ double length = std::abs((end_p - start_p).length());
+ Geom::Point anchorEnd = start_p;
+ anchorEnd[Geom::X] += length;
+ if (explicitBase) {
+ anchorEnd *= (Geom::Affine(Geom::Translate(-start_p))
+ * Geom::Affine(Geom::Rotate(baseAngle))
+ * Geom::Affine(Geom::Translate(start_p)));
+ }
+ setMeasureCanvasControlLine(start_p, anchorEnd, to_item, CTLINE_SECONDARY, measure_repr);
+ createAngleDisplayCurve(desktop, start_p, end_p, angleDisplayPt, angle, measure_repr);
+ }
- if (this->grabbed) {
- sp_canvas_item_ungrab(this->grabbed, event->button.time);
- this->grabbed = NULL;
- }
+ if (intersections.size() > 2) {
+ setMeasureCanvasControlLine(desktop->doc2dt(intersections[0]) + normal * dimension_offset, desktop->doc2dt(intersections[intersections.size() - 1]) + normal * dimension_offset, to_item, CTLINE_PRIMARY , measure_repr);
+
+ setMeasureCanvasControlLine(desktop->doc2dt(intersections[0]), desktop->doc2dt(intersections[0]) + normal * dimension_offset, to_item, CTLINE_PRIMARY , measure_repr);
- xp = 0;
- yp = 0;
- break;
- }
- default:
- break;
+ setMeasureCanvasControlLine(desktop->doc2dt(intersections[intersections.size() - 1]), desktop->doc2dt(intersections[intersections.size() - 1]) + normal * dimension_offset, to_item, CTLINE_PRIMARY , measure_repr);
}
- if (!ret) {
- ret = ToolBase::root_handler(event);
+ // call-out lines
+ for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) {
+ LabelPlacement &place = *it;
+ setMeasureCanvasControlLine(place.start, place.end, to_item, CTLINE_SECONDARY, measure_repr);
}
- return ret;
+ {
+ for (size_t idx = 1; idx < intersections.size(); ++idx) {
+ Geom::Point measure_text_pos = (intersections[idx - 1] + intersections[idx]) / 2;
+ setMeasureCanvasControlLine(desktop->doc2dt(measure_text_pos), desktop->doc2dt(measure_text_pos) - (normal * dimension_offset / 2), to_item, CTLINE_SECONDARY, measure_repr);
+ }
+ }
}
}
diff --git a/src/ui/tools/measure-tool.h b/src/ui/tools/measure-tool.h
index 9701ba6ea..3bdc9b9c4 100644
--- a/src/ui/tools/measure-tool.h
+++ b/src/ui/tools/measure-tool.h
@@ -6,41 +6,72 @@
*
* Authors:
* Felipe Correa da Silva Sanches <juca@members.fsf.org>
- *
+ * Jabiertxo Arraiza <jabier.arraiza@marker.es>
* Copyright (C) 2011 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
+#include <stddef.h>
+#include <sigc++/sigc++.h>
#include "ui/tools/tool-base.h"
#include <2geom/point.h>
+#include "display/canvas-text.h"
+#include "ui/control-manager.h"
#include <boost/optional.hpp>
#define SP_MEASURE_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::MeasureTool*>((Inkscape::UI::Tools::ToolBase*)obj))
#define SP_IS_MEASURE_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::MeasureTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)
+class SPKnot;
+
namespace Inkscape {
namespace UI {
namespace Tools {
class MeasureTool : public ToolBase {
public:
- MeasureTool();
- virtual ~MeasureTool();
-
- static const std::string prefsPath;
+ MeasureTool();
+ virtual ~MeasureTool();
- virtual void finish();
- virtual bool root_handler(GdkEvent* event);
+ static const std::string prefsPath;
- virtual const std::string& getPrefsPath();
+ virtual void finish();
+ virtual bool root_handler(GdkEvent* event);
+ virtual void showCanvasItems(bool to_guides = false, bool to_item = false, Inkscape::XML::Node *measure_repr = NULL);
+ virtual void reverseKnots();
+ virtual void toGuides();
+ virtual void toMarkDimension();
+ virtual void toItem();
+ virtual void reset();
+ virtual void setMarkers();
+ virtual void setMarker(bool isStart);
+ virtual const std::string& getPrefsPath();
+ Geom::Point readMeasurePoint(bool is_start);
+ void writeMeasurePoint(Geom::Point point, bool is_start);
+ void setGuide(Geom::Point origin, double angle, const char *label);
+ void setPoint(Geom::Point origin, Inkscape::XML::Node *measure_repr);
+ void setLine(Geom::Point start_point,Geom::Point end_point, bool markers, guint32 color, Inkscape::XML::Node *measure_repr = NULL);
+ void setMeasureCanvasText(bool is_angle, double precision, double amount, double fontsize, Glib::ustring unit_name, Geom::Point position, guint32 background, CanvasTextAnchorPositionEnum text_anchor, bool to_item, Inkscape::XML::Node *measure_repr);
+ void setMeasureCanvasItem(Geom::Point position, bool to_item, Inkscape::XML::Node *measure_repr);
+ void setMeasureCanvasControlLine(Geom::Point start, Geom::Point end, bool to_item, Inkscape::CtrlLineType ctrl_line_type, Inkscape::XML::Node *measure_repr);
+ void setLabelText(const char *value, Geom::Point pos, double fontsize, Geom::Coord angle, guint32 background , Inkscape::XML::Node *measure_repr = NULL, CanvasTextAnchorPositionEnum text_anchor = TEXT_ANCHOR_CENTER );
+ void knotStartMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state);
+ void knotEndMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state);
+ void knotUngrabbedHandler(SPKnot */*knot*/, unsigned int /*state*/);
private:
- SPCanvasItem* grabbed;
-
- Geom::Point start_point;
+ SPCanvasItem* grabbed;
boost::optional<Geom::Point> explicitBase;
- boost::optional<Geom::Point> lastEnd;
+ boost::optional<Geom::Point> last_end;
+ SPKnot *knot_start;
+ SPKnot *knot_end;
+ gint dimension_offset;
+ Geom::Point start_p;
+ Geom::Point end_p;
+ sigc::connection _knot_start_moved_connection;
+ sigc::connection _knot_start_ungrabbed_connection;
+ sigc::connection _knot_end_moved_connection;
+ sigc::connection _knot_end_ungrabbed_connection;
};
}
@@ -48,3 +79,14 @@ private:
}
#endif // SEEN_SP_MEASURING_CONTEXT_H
+
+/*
+ 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 :
diff --git a/src/widgets/measure-toolbar.cpp b/src/widgets/measure-toolbar.cpp
index 5a4785b1f..67c128dd2 100644
--- a/src/widgets/measure-toolbar.cpp
+++ b/src/widgets/measure-toolbar.cpp
@@ -33,11 +33,16 @@
#include "measure-toolbar.h"
#include "desktop.h"
+#include "inkscape.h"
+#include "message-stack.h"
#include "document-undo.h"
#include "widgets/ege-adjustment-action.h"
#include "widgets/ege-output-action.h"
#include "preferences.h"
#include "toolbox.h"
+#include "widgets/ink-action.h"
+#include "ui/icon-names.h"
+#include "ui/tools/measure-tool.h"
#include "ui/widget/unit-tracker.h"
using Inkscape::UI::Widget::UnitTracker;
@@ -45,11 +50,26 @@ using Inkscape::Util::Unit;
using Inkscape::DocumentUndo;
using Inkscape::UI::ToolboxFactory;
using Inkscape::UI::PrefPusher;
+using Inkscape::UI::Tools::MeasureTool;
//########################
//## Measure Toolbox ##
//########################
+/** Temporary hack: Returns the node tool in the active desktop.
+ * Will go away during tool refactoring. */
+static MeasureTool *get_measure_tool()
+{
+ MeasureTool *tool = 0;
+ if (SP_ACTIVE_DESKTOP ) {
+ Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
+ if (SP_IS_MEASURE_CONTEXT(ec)) {
+ tool = static_cast<MeasureTool*>(ec);
+ }
+ }
+ return tool;
+}
+
static void
sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl)
{
@@ -57,17 +77,176 @@ sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl)
if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- prefs->setInt(Glib::ustring("/tools/measure/fontsize"),
+ prefs->setDouble(Glib::ustring("/tools/measure/fontsize"),
+ gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+ }
+}
+
+static void
+sp_measure_offset_value_changed(GtkAdjustment *adj, GObject *tbl)
+{
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
+
+ if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble(Glib::ustring("/tools/measure/offset"),
gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
}
}
-static void measure_unit_changed(GtkAction* /*act*/, GObject* tbl)
+static void sp_measure_scale_value_changed(GtkAdjustment *adj, GObject *tbl)
+{
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
+
+ if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble(Glib::ustring("/tools/measure/scale"),
+ gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+ }
+}
+
+static void
+sp_measure_precision_value_changed(GtkAdjustment *adj, GObject *tbl)
+{
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
+
+ if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setInt(Glib::ustring("/tools/measure/precision"),
+ gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+ }
+}
+
+static void
+sp_measure_unit_changed(GtkAction* /*act*/, GObject* tbl)
{
UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker"));
Glib::ustring const unit = tracker->getActiveUnit()->abbr;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setString("/tools/measure/unit", unit);
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_ignore_1st_and_last( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/ignore_1st_and_last", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Start and end measures inactive."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Start and end measures active."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_only_visible( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/only_visible", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Show only visible crossings."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Show all crossings."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_all_layers( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/all_layers", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Use all layers in the measure."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Use current layer in the measure."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_show_in_between( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/show_in_between", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Compute all elements."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Compute max lenght."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+static void
+sp_reverse_knots(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->reverseKnots();
+ }
+}
+
+static void
+sp_to_mark_dimension(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->toMarkDimension();
+ }
+}
+
+static void
+sp_to_guides(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->toGuides();
+ }
+}
+
+static void
+sp_to_item(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->toItem();
+ }
}
void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder)
@@ -79,22 +258,22 @@ void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, G
g_object_set_data( holder, "tracker", tracker );
EgeAdjustmentAction *eact = 0;
+ Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
/* Font Size */
{
eact = create_adjustment_action( "MeasureFontSizeAction",
_("Font Size"), _("Font Size:"),
_("The font size to be used in the measurement labels"),
- "/tools/measure/fontsize", 0.0,
+ "/tools/measure/fontsize", 10.0,
GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
- 10, 36, 1.0, 4.0,
+ 1.0, 36.0, 1.0, 4.0,
0, 0, 0,
- sp_measure_fontsize_value_changed);
- gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ sp_measure_fontsize_value_changed, NULL, 0 , 2);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact));
}
-
- // units label
+ /* units label */
{
EgeOutputAction* act = ege_output_action_new( "measure_units_label", _("Units:"), _("The units to be used for the measurements"), 0 );
ege_output_action_set_use_markup( act, TRUE );
@@ -102,12 +281,136 @@ void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, G
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
}
- // units menu
+ /* units menu */
{
GtkAction* act = tracker->createAction( "MeasureUnitsAction", _("Units:"), _("The units to be used for the measurements") );
- g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(measure_unit_changed), holder );
+ g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_measure_unit_changed), holder );
gtk_action_group_add_action( mainActions, act );
}
+
+ /* Precission */
+ {
+ eact = create_adjustment_action( "MeasurePrecisionAction",
+ _("Precision"), _("Precision:"),
+ _("Decimal precision of measure"),
+ "/tools/measure/precision", 2,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0, 10, 1, 0,
+ 0, 0, 0,
+ sp_measure_precision_value_changed, NULL, 0 ,0);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact));
+ }
+
+ /* Scale */
+ {
+ eact = create_adjustment_action( "MeasureScaleAction",
+ _("Scale %"), _("Scale %:"),
+ _("Scale the results"),
+ "/tools/measure/scale", 100.0,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0.0, 90000.0, 1.0, 4.0,
+ 0, 0, 0,
+ sp_measure_scale_value_changed, NULL, 0 , 3);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ }
+
+ /* Offset */
+ {
+ eact = create_adjustment_action( "MeasureOffsetAction",
+ _("Offset"), _("Offset:"),
+ _("The offset size"),
+ "/tools/measure/offset", 5.0,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0.0, 90000.0, 1.0, 4.0,
+ 0, 0, 0,
+ sp_measure_offset_value_changed, NULL, 0 , 2);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ }
+
+ /* ignore_1st_and_last */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureIgnore1stAndLast",
+ _("Ignore first and last"),
+ _("Ignore first and last"),
+ INKSCAPE_ICON("draw-geometry-line-segment"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/ignore_1st_and_last", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_ignore_1st_and_last), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* only visible */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureOnlyVisible",
+ _("Only visible intersections"),
+ _("Only visible intersections"),
+ INKSCAPE_ICON("zoom"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/only_visible", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_only_visible), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* measure imbetweens */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureInBettween",
+ _("Show measures between items"),
+ _("Show measures between items"),
+ INKSCAPE_ICON("distribute-randomize"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/show_in_between", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_show_in_between), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* measure only current layer */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureAllLayers",
+ _("Measure all layers"),
+ _("Measure all layers"),
+ INKSCAPE_ICON("dialog-layers"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/all_layers", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_all_layers), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* toogle start end */
+ {
+ InkAction* act = ink_action_new( "MeasureReverse",
+ _("Reverse measure"),
+ _("Reverse measure"),
+ INKSCAPE_ICON("draw-geometry-mirror"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_reverse_knots), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* to guides */
+ {
+ InkAction* act = ink_action_new( "MeasureToGuides",
+ _("To guides"),
+ _("To guides"),
+ INKSCAPE_ICON("guides"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_guides), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* to mark dimensions */
+ {
+ InkAction* act = ink_action_new( "MeasureMarkDimension",
+ _("Mark Dimension"),
+ _("Mark Dimension"),
+ INKSCAPE_ICON("tool-pointer"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_mark_dimension), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* to item */
+ {
+ InkAction* act = ink_action_new( "MeasureToItem",
+ _("Convert to item"),
+ _("Convert to item"),
+ INKSCAPE_ICON("path-reverse"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_item), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
} // end of sp_measure_toolbox_prep()
diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp
index a1c32352c..90103325a 100644
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
@@ -339,8 +339,22 @@ static gchar const * ui_descr =
" <toolbar name='MeasureToolbar'>"
" <toolitem action='MeasureFontSizeAction' />"
" <separator />"
+ " <toolitem action='MeasurePrecisionAction' />"
+ " <separator />"
+ " <toolitem action='MeasureScaleAction' />"
+ " <separator />"
+ " <toolitem action='MeasureOffsetAction' />"
+ " <separator />"
" <toolitem action='measure_units_label' />"
" <toolitem action='MeasureUnitsAction' />"
+ " <toolitem action='MeasureIgnore1stAndLast' />"
+ " <toolitem action='MeasureInBettween' />"
+ " <toolitem action='MeasureOnlyVisible' />"
+ " <toolitem action='MeasureAllLayers' />"
+ " <toolitem action='MeasureReverse' />"
+ " <toolitem action='MeasureToGuides' />"
+ " <toolitem action='MeasureMarkDimension' />"
+ " <toolitem action='MeasureToItem' />"
" </toolbar>"
" <toolbar name='StarToolbar'>"