summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: af768e2)
raw | patch | inline | side by side (parent: af768e2)
author | Krzysztof Kosiński <tweenk.pl@gmail.com> | |
Thu, 18 Mar 2010 02:18:56 +0000 (03:18 +0100) | ||
committer | Krzysztof Kosiński <tweenk.pl@gmail.com> | |
Thu, 18 Mar 2010 02:18:56 +0000 (03:18 +0100) |
src/ui/tool/node.cpp | patch | blob | history | |
src/ui/tool/node.h | patch | blob | history | |
src/ui/tool/path-manipulator.cpp | patch | blob | history |
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index c82b0c7d6a7466d6ca390a50ac433c5d6c645f2d..e9fa79fb3bb4d3c1b8ac603675245a51e6cd6984 100644 (file)
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
void Handle::move(Geom::Point const &new_pos)
{
- Handle *other, *towards, *towards_second;
- Node *node_towards; // node in direction of this handle
- Node *node_away; // node in the opposite direction
- if (this == &_parent->_front) {
- other = &_parent->_back;
- node_towards = _parent->_next();
- node_away = _parent->_prev();
- towards = node_towards ? &node_towards->_back : 0;
- towards_second = node_towards ? &node_towards->_front : 0;
- } else {
- other = &_parent->_front;
- node_towards = _parent->_prev();
- node_away = _parent->_next();
- towards = node_towards ? &node_towards->_front : 0;
- towards_second = node_towards ? &node_towards->_back : 0;
- }
+ Handle *other = this->other();
+ Node *node_towards = _parent->nodeToward(this); // node in direction of this handle
+ Node *node_away = _parent->nodeAwayFrom(this); // node in the opposite direction
+ Handle *towards = node_towards ? node_towards->handleAwayFrom(_parent) : NULL;
+ Handle *towards_second = node_towards ? node_towards->handleToward(_parent) : NULL;
if (Geom::are_near(new_pos, _parent->position())) {
// The handle becomes degenerate. If the segment between it and the node
bool Handle::grabbed(GdkEventMotion *)
{
- _saved_other_pos = other().position();
+ _saved_other_pos = other()->position();
_saved_length = _drag_out ? 0 : length();
_pm()._handleGrabbed();
return false;
if (held_shift(*event)) {
Geom::Point other_relpos = _saved_other_pos - parent_pos;
other_relpos *= Geom::Rotate(Geom::angle_between(origin - parent_pos, new_pos - parent_pos));
- other().setRelativePos(other_relpos);
+ other()->setRelativePos(other_relpos);
} else {
// restore the position
- other().setPosition(_saved_other_pos);
+ other()->setPosition(_saved_other_pos);
}
}
move(new_pos); // needed for correct update, even though it's redundant
return true;
}
-Handle &Handle::other()
+Handle *Handle::other()
{
- if (this == &_parent->_front) return _parent->_back;
- return _parent->_front;
+ if (this == &_parent->_front) return &_parent->_back;
+ return &_parent->_front;
}
static double snap_increment_degrees() {
Glib::ustring Handle::_getTip(unsigned state)
{
char const *more;
- bool can_shift_rotate = _parent->type() == NODE_CUSP && !other().isDegenerate();
+ bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate();
if (can_shift_rotate) {
more = C_("Path handle tip", "more: Shift, Ctrl, Alt");
} else {
return SNAPTARGET_NODE_CUSP;
}
+/** @brief 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) {
+ return front();
+ }
+ if (_prev() == to) {
+ return back();
+ }
+ g_error("Node::handleToward(): second node is not adjacent!");
+}
+
+/** @brief 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) {
+ return _next();
+ }
+ if (back() == dir) {
+ return _prev();
+ }
+ g_error("Node::nodeToward(): handle is not a child of this node!");
+}
+
+/** @brief 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) {
+ return back();
+ }
+ if (_prev() == to) {
+ return front();
+ }
+ g_error("Node::handleAwayFrom(): second node is not adjacent!");
+}
+
+/** @brief 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) {
+ return _prev();
+ }
+ if (back() == h) {
+ return _next();
+ }
+ g_error("Node::nodeAwayFrom(): handle is not a child of this node!");
+}
+
Glib::ustring Node::_getTip(unsigned state)
{
if (state_held_shift(state)) {
"<b>Ctrl:</b> move along axes, click to change node type");
}
- // assemble tip from node name
+ if (state_held_alt(state)) {
+ return C_("Path node tip", "<b>Alt:</b> sculpt nodes");
+ }
+
+ // No modifiers: assemble tip from node type
char const *nodetype = node_type_to_localized_string(_type);
if (_selection.transformHandlesEnabled() && selected()) {
if (_selection.size() == 1) {
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index d04b879761faf99adb3d4db7f8093b5311c054c5..af4cd7e3af1c5b09f4d3bbd67b204cfda14480fa 100644 (file)
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
void setDirection(Geom::Point const &from, Geom::Point const &to);
void setDirection(Geom::Point const &dir);
Node *parent() { return _parent; }
- Handle &other();
+ Handle *other();
static char const *handle_type_to_localized_string(NodeType type);
protected:
bool isEndNode();
Handle *front() { return &_front; }
Handle *back() { return &_back; }
- static NodeType parse_nodetype(char x);
+ Handle *handleToward(Node *to);
+ Node *nodeToward(Handle *h);
+ Handle *handleAwayFrom(Node *to);
+ Node *nodeAwayFrom(Handle *h);
NodeList &nodeList() { return *(static_cast<ListNode*>(this)->ln_list); }
void sink();
+ static NodeType parse_nodetype(char x);
static char const *node_type_to_localized_string(NodeType type);
// temporarily public
virtual bool _eventHandler(GdkEvent *event);
index ebf0f3828c07291159a4242c376aa0a18b3ce274..f6d5bde37124654d85b22d03773f55a8be6b108b 100644 (file)
case SEGMENT_CUBIC_BEZIER:
if (!j->front()->isDegenerate() || !k->back()->isDegenerate())
break;
+ // move both handles to 1/3 of the line
j->front()->move(j->position() + (k->position() - j->position()) / 3);
k->back()->move(k->position() + (j->position() - k->position()) / 3);
break;
length_change *= dir;
}
- Geom::Point relpos = h->relativePos();
- double rellen = relpos.length();
- h->setRelativePos(relpos * ((rellen + length_change) / rellen));
+ Geom::Point relpos;
+ if (h->isDegenerate()) {
+ Node *nh = n->nodeToward(h);
+ if (!nh) return;
+ relpos = Geom::unit_vector(nh->position() - n->position()) * length_change;
+ } else {
+ relpos = h->relativePos();
+ double rellen = relpos.length();
+ relpos *= ((rellen + length_change) / rellen);
+ }
+ h->setRelativePos(relpos);
update();
gchar const *key = which < 0 ? "handle:scale:left" : "handle:scale:right";
n->setType(NODE_CUSP);
}
Handle *h = _chooseHandle(n, which);
- double angle;
+ if (h->isDegenerate()) return;
+ double angle;
if (pixel) {
// Rotate by "one pixel"
angle = atan2(1.0 / _desktop->current_zoom(), h->length()) * dir;
int snaps = prefs->getIntLimited("/options/rotationsnapsperpi/value", 12, 1, 1000);
angle = M_PI * dir / snaps;
}
+
h->setRelativePos(h->relativePos() * Geom::Rotate(angle));
update();
gchar const *key = which < 0 ? "handle:rotate:left" : "handle:rotate:right";
Handle *PathManipulator::_chooseHandle(Node *n, int which)
{
- Geom::Point f = n->front()->position(), b = n->back()->position();
+ // Rationale for this choice:
+ // Imagine you have two handles pointing right, where one of them is only slighty higher
+ // than the other. Extending one of the handles could make its X coord larger than
+ // the second one, and keeping the shortcut pressed would result in two handles being
+ // extended alternately. This appears like extending both handles at once and is confusing.
+ // Using the unit vector avoids this problem and remains fairly intuitive.
+ Geom::Point f = Geom::unit_vector(n->front()->position());
+ Geom::Point b = Geom::unit_vector(n->back()->position());
if (which < 0) {
// pick left handle.
// we just swap the handles and pick the right handle below.