summaryrefslogtreecommitdiffstats
path: root/src/ui/tool/node.cpp
diff options
context:
space:
mode:
authorMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
committerMartin Owens <doctormo@gmail.com>2014-03-27 01:33:44 +0000
commit5a4fb2325f60d292b47330f540b26a3279341c90 (patch)
treed2aa7967be25450b83e625025366c618101ae49f /src/ui/tool/node.cpp
parentThe Polar Arrange Tab of the Arrange Dialog now hides the parametric (diff)
parentRemove Snap menu item and improve grid menu item text (diff)
downloadinkscape-5a4fb2325f60d292b47330f540b26a3279341c90.tar.gz
inkscape-5a4fb2325f60d292b47330f540b26a3279341c90.zip
Commit a merge to trunk, with probabal errors
(bzr r11073.1.36)
Diffstat (limited to 'src/ui/tool/node.cpp')
-rw-r--r--src/ui/tool/node.cpp302
1 files changed, 158 insertions, 144 deletions
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index ad48b523b..fbbc4be64 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -1,7 +1,3 @@
-/**
- * @file
- * Editable node - implementation.
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
* Jon A. Cruz <jon@joncruz.org>
@@ -26,33 +22,57 @@
#include "preferences.h"
#include "snap.h"
#include "snap-preferences.h"
-#include "sp-metrics.h"
#include "sp-namedview.h"
+#include "ui/control-manager.h"
#include "ui/tool/control-point-selection.h"
#include "ui/tool/event-utils.h"
#include "ui/tool/node.h"
#include "ui/tool/path-manipulator.h"
#include <gdk/gdkkeysyms.h>
-#if !GTK_CHECK_VERSION(2,22,0)
-#include "compat-key-syms.h"
-#endif
+namespace {
+
+Inkscape::ControlType nodeTypeToCtrlType(Inkscape::UI::NodeType type)
+{
+ Inkscape::ControlType result = Inkscape::CTRL_TYPE_NODE_CUSP;
+ switch(type) {
+ case Inkscape::UI::NODE_SMOOTH:
+ result = Inkscape::CTRL_TYPE_NODE_SMOOTH;
+ break;
+ case Inkscape::UI::NODE_AUTO:
+ result = Inkscape::CTRL_TYPE_NODE_AUTO;
+ break;
+ case Inkscape::UI::NODE_SYMMETRIC:
+ result = Inkscape::CTRL_TYPE_NODE_SYMETRICAL;
+ break;
+ case Inkscape::UI::NODE_CUSP:
+ default:
+ result = Inkscape::CTRL_TYPE_NODE_CUSP;
+ break;
+ }
+ return result;
+}
+
+} // namespace
namespace Inkscape {
namespace UI {
-static SelectableControlPoint::ColorSet node_colors = {
- {
- {0xbfbfbf00, 0x000000ff}, // normal fill, stroke
- {0xff000000, 0x000000ff}, // mouseover fill, stroke
- {0xff000000, 0x000000ff} // clicked fill, stroke
- },
+ControlPoint::ColorSet Node::node_colors = {
+ {0xbfbfbf00, 0x000000ff}, // normal fill, stroke
+ {0xff000000, 0x000000ff}, // mouseover fill, stroke
+ {0xff000000, 0x000000ff}, // clicked fill, stroke
+ //
{0x0000ffff, 0x000000ff}, // normal fill, stroke when selected
{0xff000000, 0x000000ff}, // mouseover fill, stroke when selected
{0xff000000, 0x000000ff} // clicked fill, stroke when selected
};
-static ControlPoint::ColorSet handle_colors = {
+ControlPoint::ColorSet Handle::_handle_colors = {
+ {0xffffffff, 0x000000ff}, // normal fill, stroke
+ {0xff000000, 0x000000ff}, // mouseover fill, stroke
+ {0xff000000, 0x000000ff}, // clicked fill, stroke
+ //
{0xffffffff, 0x000000ff}, // normal fill, stroke
{0xff000000, 0x000000ff}, // mouseover fill, stroke
{0xff000000, 0x000000ff} // clicked fill, stroke
@@ -75,30 +95,27 @@ static Geom::Point direction(Geom::Point const &first, Geom::Point const &second
return Geom::unit_vector(second - first);
}
-/**
- * Control point of a cubic Bezier curve in a path.
- *
- * Handle keeps the node type invariant only for the opposite handle of the same node.
- * Keeping the invariant on node moves is left to the %Node class.
- */
Geom::Point Handle::_saved_other_pos(0, 0);
+
double Handle::_saved_length = 0.0;
+
bool Handle::_drag_out = false;
-Handle::Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent)
- : ControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER, SP_CTRL_SHAPE_CIRCLE, 7.0,
- &handle_colors, data.handle_group)
- , _parent(parent)
- , _degenerate(true)
+Handle::Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent) :
+ ControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER,
+ CTRL_TYPE_ADJ_HANDLE,
+ _handle_colors, data.handle_group),
+ _parent(parent),
+ _handle_line(ControlManager::getManager().createControlLine(data.handle_line_group)),
+ _degenerate(true)
{
- _cset = &handle_colors;
- _handle_line = SP_CTRLLINE(sp_canvas_item_new(data.handle_line_group, SP_TYPE_CTRLLINE, NULL));
setVisible(false);
}
+
Handle::~Handle()
{
//sp_canvas_item_hide(_handle_line);
- gtk_object_destroy(_handle_line);
+ sp_canvas_item_destroy(_handle_line);
}
void Handle::setVisible(bool v)
@@ -233,7 +250,7 @@ char const *Handle::handle_type_to_localized_string(NodeType type)
}
}
-bool Handle::_eventHandler(SPEventContext *event_context, GdkEvent *event)
+bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event)
{
switch (event->type)
{
@@ -275,7 +292,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
Geom::Point parent_pos = _parent->position();
Geom::Point origin = _last_drag_origin();
SnapManager &sm = _desktop->namedview->snap_manager;
- bool snap = sm.someSnapperMightSnap();
+ bool snap = held_shift(*event) ? false : sm.someSnapperMightSnap();
boost::optional<Inkscape::Snapper::SnapConstraint> ctrl_constraint;
// with Alt, preserve length
@@ -387,10 +404,18 @@ bool Handle::clicked(GdkEventButton *event)
return true;
}
+Handle const *Handle::other() const
+{
+ return const_cast<Handle *>(this)->other();
+}
+
Handle *Handle::other()
{
- if (this == &_parent->_front) return &_parent->_back;
- return &_parent->_front;
+ if (this == &_parent->_front) {
+ return &_parent->_back;
+ } else {
+ return &_parent->_front;
+ }
}
static double snap_increment_degrees() {
@@ -399,7 +424,7 @@ static double snap_increment_degrees() {
return 180.0 / snaps;
}
-Glib::ustring Handle::_getTip(unsigned state)
+Glib::ustring Handle::_getTip(unsigned state) const
{
char const *more;
bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate();
@@ -457,16 +482,20 @@ Glib::ustring Handle::_getTip(unsigned state)
}
}
-Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/)
+Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/) const
{
Geom::Point dist = position() - _last_drag_origin();
// report angle in mathematical convention
double angle = Geom::angle_between(Geom::Point(-1,0), position() - _parent->position());
angle += M_PI; // angle is (-M_PI...M_PI] - offset by +pi and scale to 0...360
angle *= 360.0 / (2 * M_PI);
- GString *x = SP_PX_TO_METRIC_STRING(dist[Geom::X], _desktop->namedview->getDefaultMetric());
- GString *y = SP_PX_TO_METRIC_STRING(dist[Geom::Y], _desktop->namedview->getDefaultMetric());
- GString *len = SP_PX_TO_METRIC_STRING(length(), _desktop->namedview->getDefaultMetric());
+
+ Inkscape::Util::Quantity x_q = Inkscape::Util::Quantity(dist[Geom::X], "px");
+ Inkscape::Util::Quantity y_q = Inkscape::Util::Quantity(dist[Geom::Y], "px");
+ Inkscape::Util::Quantity len_q = Inkscape::Util::Quantity(length(), "px");
+ GString *x = g_string_new(x_q.string(_desktop->namedview->doc_units).c_str());
+ GString *y = g_string_new(y_q.string(_desktop->namedview->doc_units).c_str());
+ GString *len = g_string_new(len_q.string(_desktop->namedview->doc_units).c_str());
Glib::ustring ret = format_tip(C_("Path handle tip",
"Move handle by %s, %s; angle %.2f°, length %s"), x->str, y->str, angle, len->str);
g_string_free(x, TRUE);
@@ -475,34 +504,48 @@ Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/)
return ret;
}
-/**
- * Curve endpoint in an editable path.
- *
- * The method move() keeps node type invariants during translations.
- */
-Node::Node(NodeSharedData const &data, Geom::Point const &initial_pos)
- : SelectableControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER,
- SP_CTRL_SHAPE_DIAMOND, 9.0, *data.selection, &node_colors, data.node_group)
- , _front(data, initial_pos, this)
- , _back(data, initial_pos, this)
- , _type(NODE_CUSP)
- , _handles_shown(false)
+Node::Node(NodeSharedData const &data, Geom::Point const &initial_pos) :
+ SelectableControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER,
+ CTRL_TYPE_NODE_CUSP,
+ *data.selection,
+ node_colors, data.node_group),
+ _front(data, initial_pos, this),
+ _back(data, initial_pos, this),
+ _type(NODE_CUSP),
+ _handles_shown(false)
{
// NOTE we do not set type here, because the handles are still degenerate
}
+Node const *Node::_next() const
+{
+ return const_cast<Node*>(this)->_next();
+}
+
// NOTE: not using iterators won't make this much quicker because iterators can be 100% inlined.
Node *Node::_next()
{
NodeList::iterator n = NodeList::get_iterator(this).next();
- if (n) return n.ptr();
- return NULL;
+ if (n) {
+ return n.ptr();
+ } else {
+ return NULL;
+ }
+}
+
+Node const *Node::_prev() const
+{
+ return const_cast<Node *>(this)->_prev();
}
+
Node *Node::_prev()
{
NodeList::iterator p = NodeList::get_iterator(this).prev();
- if (p) return p.ptr();
- return NULL;
+ if (p) {
+ return p.ptr();
+ } else {
+ return NULL;
+ }
}
void Node::move(Geom::Point const &new_pos)
@@ -531,7 +574,7 @@ void Node::transform(Geom::Affine const &m)
_fixNeighbors(old_pos, position());
}
-Geom::Rect Node::bounds()
+Geom::Rect Node::bounds() const
{
Geom::Rect b(position(), position());
b.expandTo(_front.position());
@@ -608,17 +651,23 @@ void Node::_updateAutoHandles()
void Node::showHandles(bool v)
{
_handles_shown = v;
- if (!_front.isDegenerate()) _front.setVisible(v);
- if (!_back.isDegenerate()) _back.setVisible(v);
+ if (!_front.isDegenerate()) {
+ _front.setVisible(v);
+ }
+ if (!_back.isDegenerate()) {
+ _back.setVisible(v);
+ }
}
-/** Sets the node type and optionally restores the invariants associated with the given type.
- * @param type The type to set
- * @param update_handles Whether to restore invariants associated with the given type.
- * Passing false is useful e.g. wen initially creating the path,
- * and when making cusp nodes during some node algorithms.
- * Pass true when used in response to an UI node type button.
- */
+void Node::updateHandles()
+{
+ _handleControlStyling();
+
+ _front._handleControlStyling();
+ _back._handleControlStyling();
+}
+
+
void Node::setType(NodeType type, bool update_handles)
{
if (type == NODE_PICK_BEST) {
@@ -711,12 +760,10 @@ void Node::setType(NodeType type, bool update_handles)
}
}
_type = type;
- _setShape(_node_type_to_shape(type));
+ _setControlType(nodeTypeToCtrlType(_type));
updateState();
}
-/** Pick the best type for this node, based on the position of its handles.
- * This is what assigns types to nodes created using the pen tool. */
void Node::pickBestType()
{
_type = NODE_CUSP;
@@ -762,17 +809,15 @@ void Node::pickBestType()
}
}
} while (false);
- _setShape(_node_type_to_shape(_type));
+ _setControlType(nodeTypeToCtrlType(_type));
updateState();
}
-bool Node::isEndNode()
+bool Node::isEndNode() const
{
return !_prev() || !_next();
}
-/** Move the node to the bottom of its canvas group. Useful for node break, to ensure that
- * the selected nodes are above the unselected ones. */
void Node::sink()
{
sp_canvas_item_move_to_z(_canvas_item, 0);
@@ -789,8 +834,7 @@ NodeType Node::parse_nodetype(char x)
}
}
-/** Customized event handler to catch scroll events needed for selection grow/shrink. */
-bool Node::_eventHandler(SPEventContext *event_context, GdkEvent *event)
+bool Node::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event)
{
int dir = 0;
@@ -834,8 +878,6 @@ bool Node::_eventHandler(SPEventContext *event_context, GdkEvent *event)
return ControlPoint::_eventHandler(event_context, event);
}
-/** Select or deselect a node in this node's subpath based on its path distance from this node.
- * @param dir If negative, shrink selection by one node; if positive, grow by one node */
void Node::_linearGrow(int dir)
{
// Interestingly, we do not need any help from PathManipulator when doing linear grow.
@@ -948,29 +990,36 @@ void Node::_linearGrow(int dir)
void Node::_setState(State state)
{
// change node size to match type and selection state
- switch (_type) {
- case NODE_AUTO:
- case NODE_CUSP:
- if (selected()) _setSize(11);
- else _setSize(9);
- break;
- default:
- if(selected()) _setSize(9);
- else _setSize(7);
- break;
+ ControlManager &mgr = ControlManager::getManager();
+ mgr.setSelected(_canvas_item, selected());
+ switch (state) {
+ case STATE_NORMAL:
+ mgr.setActive(_canvas_item, false);
+ mgr.setPrelight(_canvas_item, false);
+ break;
+ case STATE_MOUSEOVER:
+ mgr.setActive(_canvas_item, false);
+ mgr.setPrelight(_canvas_item, true);
+ break;
+ case STATE_CLICKED:
+ mgr.setActive(_canvas_item, true);
+ mgr.setPrelight(_canvas_item, false);
+ break;
}
SelectableControlPoint::_setState(state);
}
bool Node::grabbed(GdkEventMotion *event)
{
- if (SelectableControlPoint::grabbed(event))
+ if (SelectableControlPoint::grabbed(event)) {
return true;
+ }
// Dragging out handles with Shift + drag on a node.
- if (!held_shift(*event)) return false;
+ if (!held_shift(*event)) {
+ return false;
+ }
- Handle *h;
Geom::Point evp = event_point(*event);
Geom::Point rel_evp = evp - _last_click_event_point();
@@ -991,8 +1040,11 @@ bool Node::grabbed(GdkEventMotion *event)
angle_prev = fabs(Geom::angle_between(rel_evp, prev_relpos));
has_degenerate = true;
}
- if (!has_degenerate) return false;
- h = angle_next < angle_prev ? &_front : &_back;
+ if (!has_degenerate) {
+ return false;
+ }
+
+ Handle *h = angle_next < angle_prev ? &_front : &_back;
h->setPosition(_desktop->w2d(evp));
h->setVisible(true);
@@ -1138,13 +1190,13 @@ bool Node::clicked(GdkEventButton *event)
return SelectableControlPoint::clicked(event);
}
-Inkscape::SnapSourceType Node::_snapSourceType()
+Inkscape::SnapSourceType Node::_snapSourceType() const
{
if (_type == NODE_SMOOTH || _type == NODE_AUTO)
return SNAPSOURCE_NODE_SMOOTH;
return SNAPSOURCE_NODE_CUSP;
}
-Inkscape::SnapTargetType Node::_snapTargetType()
+Inkscape::SnapTargetType Node::_snapTargetType() const
{
if (_type == NODE_SMOOTH || _type == NODE_AUTO)
return SNAPTARGET_NODE_SMOOTH;
@@ -1156,10 +1208,6 @@ Inkscape::SnapCandidatePoint Node::snapCandidatePoint()
return SnapCandidatePoint(position(), _snapSourceType(), _snapTargetType());
}
-/**
- * Gets the handle that faces the given adjacent node.
- * Will abort with error if the given node is not adjacent.
- */
Handle *Node::handleToward(Node *to)
{
if (_next() == to) {
@@ -1169,12 +1217,9 @@ Handle *Node::handleToward(Node *to)
return back();
}
g_error("Node::handleToward(): second node is not adjacent!");
+ return NULL;
}
-/**
- * Gets the node in the direction of the given handle.
- * Will abort with error if the handle doesn't belong to this node.
- */
Node *Node::nodeToward(Handle *dir)
{
if (front() == dir) {
@@ -1184,12 +1229,9 @@ Node *Node::nodeToward(Handle *dir)
return _prev();
}
g_error("Node::nodeToward(): handle is not a child of this node!");
+ return NULL;
}
-/**
- * Gets the handle that goes in the direction opposite to the given adjacent node.
- * Will abort with error if the given node is not adjacent.
- */
Handle *Node::handleAwayFrom(Node *to)
{
if (_next() == to) {
@@ -1199,12 +1241,9 @@ Handle *Node::handleAwayFrom(Node *to)
return front();
}
g_error("Node::handleAwayFrom(): second node is not adjacent!");
+ return NULL;
}
-/**
- * Gets the node in the direction opposite to the given handle.
- * Will abort with error if the handle doesn't belong to this node.
- */
Node *Node::nodeAwayFrom(Handle *h)
{
if (front() == h) {
@@ -1214,9 +1253,10 @@ Node *Node::nodeAwayFrom(Handle *h)
return _next();
}
g_error("Node::nodeAwayFrom(): handle is not a child of this node!");
+ return NULL;
}
-Glib::ustring Node::_getTip(unsigned state)
+Glib::ustring Node::_getTip(unsigned state) const
{
if (state_held_shift(state)) {
bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate());
@@ -1258,13 +1298,15 @@ Glib::ustring Node::_getTip(unsigned state)
"<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype);
}
-Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/)
+Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/) const
{
Geom::Point dist = position() - _last_drag_origin();
- GString *x = SP_PX_TO_METRIC_STRING(dist[Geom::X], _desktop->namedview->getDefaultMetric());
- GString *y = SP_PX_TO_METRIC_STRING(dist[Geom::Y], _desktop->namedview->getDefaultMetric());
- Glib::ustring ret = format_tip(C_("Path node tip", "Move node by %s, %s"),
- x->str, y->str);
+
+ Inkscape::Util::Quantity x_q = Inkscape::Util::Quantity(dist[Geom::X], "px");
+ Inkscape::Util::Quantity y_q = Inkscape::Util::Quantity(dist[Geom::Y], "px");
+ GString *x = g_string_new(x_q.string(_desktop->namedview->doc_units).c_str());
+ GString *y = g_string_new(y_q.string(_desktop->namedview->doc_units).c_str());
+ Glib::ustring ret = format_tip(C_("Path node tip", "Move node by %s, %s"), x->str, y->str);
g_string_free(x, TRUE);
g_string_free(y, TRUE);
return ret;
@@ -1281,7 +1323,6 @@ char const *Node::node_type_to_localized_string(NodeType type)
}
}
-/** Determine whether two nodes are joined by a linear segment. */
bool Node::_is_line_segment(Node *first, Node *second)
{
if (!first || !second) return false;
@@ -1292,25 +1333,6 @@ bool Node::_is_line_segment(Node *first, Node *second)
return false;
}
-SPCtrlShapeType Node::_node_type_to_shape(NodeType type)
-{
- switch(type) {
- case NODE_CUSP: return SP_CTRL_SHAPE_DIAMOND;
- case NODE_SMOOTH: return SP_CTRL_SHAPE_SQUARE;
- case NODE_AUTO: return SP_CTRL_SHAPE_CIRCLE;
- case NODE_SYMMETRIC: return SP_CTRL_SHAPE_SQUARE;
- default: return SP_CTRL_SHAPE_DIAMOND;
- }
-}
-
-
-/**
- * An editable list of nodes representing a subpath.
- *
- * It can optionally be cyclic to represent a closed path.
- * The list has iterators that act like plain node iterators, but can also be used
- * to obtain shared pointers to nodes.
- */
NodeList::NodeList(SubpathList &splist)
: _list(splist)
, _closed(false)
@@ -1342,8 +1364,6 @@ bool NodeList::closed()
return _closed;
}
-/** A subpath is degenerate if it has no segments - either one node in an open path
- * or no nodes in a closed path */
bool NodeList::degenerate()
{
return closed() ? empty() : ++begin() == end();
@@ -1360,10 +1380,9 @@ NodeList::iterator NodeList::before(double t, double *fracpart)
return ret;
}
-// insert a node before i
-NodeList::iterator NodeList::insert(iterator i, Node *x)
+NodeList::iterator NodeList::insert(iterator pos, Node *x)
{
- ListNode *ins = i._node;
+ ListNode *ins = pos._node;
x->ln_next = ins;
x->ln_prev = ins->ln_prev;
ins->ln_prev->ln_next = x;
@@ -1469,11 +1488,6 @@ NodeList &NodeList::get(iterator const &i) {
}
-/**
- * @class SubpathList
- * Editable path composed of one or more subpaths.
- */
-
} // namespace UI
} // namespace Inkscape