From f9bae70725cf580c4481adac8b59aadbb935a045 Mon Sep 17 00:00:00 2001 From: buliabyak Date: Tue, 17 Apr 2007 20:57:57 +0000 Subject: [PATCH] flipping patch by maximilian albert --- src/nodepath.cpp | 43 ++++++++++++++++++++++++++++--------------- src/nodepath.h | 7 ++++++- src/seltrans.h | 6 +++++- src/shape-editor.cpp | 4 ++-- src/shape-editor.h | 3 ++- src/verbs.cpp | 35 ++++++++++++++++++++++++++++++++--- 6 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/nodepath.cpp b/src/nodepath.cpp index 32e302e33..0ad4c66a0 100644 --- a/src/nodepath.cpp +++ b/src/nodepath.cpp @@ -136,7 +136,7 @@ static Inkscape::NodePath::NodeSide *sp_node_opposite_side(Inkscape::NodePath::N static NRPathcode sp_node_path_code_from_side(Inkscape::NodePath::Node *node,Inkscape::NodePath::NodeSide *me); // active_node indicates mouseover node -static Inkscape::NodePath::Node *active_node = NULL; +Inkscape::NodePath::Node * Inkscape::NodePath::Path::active_node = NULL; /** * \brief Creates new nodepath from item @@ -2897,10 +2897,10 @@ static gboolean node_event(SPKnot *knot, GdkEvent *event, Inkscape::NodePath::No gboolean ret = FALSE; switch (event->type) { case GDK_ENTER_NOTIFY: - active_node = n; + Inkscape::NodePath::Path::active_node = n; break; case GDK_LEAVE_NOTIFY: - active_node = NULL; + Inkscape::NodePath::Path::active_node = NULL; break; case GDK_SCROLL: if ((event->scroll.state & GDK_CONTROL_MASK) && !(event->scroll.state & GDK_SHIFT_MASK)) { // linearly @@ -2971,33 +2971,33 @@ gboolean node_key(GdkEvent *event) Inkscape::NodePath::Path *np; // there is no way to verify nodes so set active_node to nil when deleting!! - if (active_node == NULL) return FALSE; + if (Inkscape::NodePath::Path::active_node == NULL) return FALSE; if ((event->type == GDK_KEY_PRESS) && !(event->key.state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) { gint ret = FALSE; switch (get_group0_keyval (&event->key)) { /// \todo FIXME: this does not seem to work, the keys are stolen by tool contexts! case GDK_BackSpace: - np = active_node->subpath->nodepath; - sp_nodepath_node_destroy(active_node); + np = Inkscape::NodePath::Path::active_node->subpath->nodepath; + sp_nodepath_node_destroy(Inkscape::NodePath::Path::active_node); sp_nodepath_update_repr(np, _("Delete node")); - active_node = NULL; + Inkscape::NodePath::Path::active_node = NULL; ret = TRUE; break; case GDK_c: - sp_nodepath_set_node_type(active_node,Inkscape::NodePath::NODE_CUSP); + sp_nodepath_set_node_type(Inkscape::NodePath::Path::active_node,Inkscape::NodePath::NODE_CUSP); ret = TRUE; break; case GDK_s: - sp_nodepath_set_node_type(active_node,Inkscape::NodePath::NODE_SMOOTH); + sp_nodepath_set_node_type(Inkscape::NodePath::Path::active_node,Inkscape::NodePath::NODE_SMOOTH); ret = TRUE; break; case GDK_y: - sp_nodepath_set_node_type(active_node,Inkscape::NodePath::NODE_SYMM); + sp_nodepath_set_node_type(Inkscape::NodePath::Path::active_node,Inkscape::NodePath::NODE_SYMM); ret = TRUE; break; case GDK_b: - sp_nodepath_node_break(active_node); + sp_nodepath_node_break(Inkscape::NodePath::Path::active_node); ret = TRUE; break; } @@ -3513,6 +3513,16 @@ static gboolean node_handle_event(SPKnot *knot, GdkEvent *event,Inkscape::NodePa break; } break; + case GDK_ENTER_NOTIFY: + // we use an experimentally determined threshold that seems to work fine + if (NR::L2(n->pos - knot->pos) < 0.75) + Inkscape::NodePath::Path::active_node = n; + break; + case GDK_LEAVE_NOTIFY: + // we use an experimentally determined threshold that seems to work fine + if (NR::L2(n->pos - knot->pos) < 0.75) + Inkscape::NodePath::Path::active_node = NULL; + break; default: break; } @@ -3803,11 +3813,11 @@ void sp_nodepath_selected_nodes_scale_screen(Inkscape::NodePath::Path *nodepath, /** * Flip selected nodes horizontally/vertically. */ -void sp_nodepath_flip (Inkscape::NodePath::Path *nodepath, NR::Dim2 axis) +void sp_nodepath_flip (Inkscape::NodePath::Path *nodepath, NR::Dim2 axis, NR::Maybe center) { if (!nodepath || !nodepath->selected) return; - if (g_list_length(nodepath->selected) == 1) { + if (g_list_length(nodepath->selected) == 1 && !center) { // flip handles of the single selected node Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) nodepath->selected->data; double temp = n->p.pos[axis]; @@ -3824,10 +3834,13 @@ void sp_nodepath_flip (Inkscape::NodePath::Path *nodepath, NR::Dim2 axis) box.expandTo (n->pos); // contain all selected nodes } + if (!center) { + center = box.midpoint(); + } NR::Matrix t = - NR::Matrix (NR::translate(-box.midpoint())) * + NR::Matrix (NR::translate(- *center)) * NR::Matrix ((axis == NR::X)? NR::scale(-1, 1) : NR::scale(1, -1)) * - NR::Matrix (NR::translate(box.midpoint())); + NR::Matrix (NR::translate(*center)); for (GList *l = nodepath->selected; l != NULL; l = l->next) { Inkscape::NodePath::Node *n = (Inkscape::NodePath::Node *) l->data; diff --git a/src/nodepath.h b/src/nodepath.h index 46d768b63..967650818 100644 --- a/src/nodepath.h +++ b/src/nodepath.h @@ -134,6 +134,11 @@ class Path { /// true if we're showing selected nodes' handles bool show_handles; + + /// active_node points to the node that is currently mouseovered (= NULL if + /// there isn't any); we also consider the node mouseovered if it is covered + /// by one of its handles and the latter is mouseovered + static Node *active_node; }; @@ -285,6 +290,6 @@ void sp_nodepath_selected_nodes_rotate (Inkscape::NodePath::Path * nodepath, gdo void sp_nodepath_selected_nodes_scale (Inkscape::NodePath::Path * nodepath, gdouble grow, int which); void sp_nodepath_selected_nodes_scale_screen (Inkscape::NodePath::Path * nodepath, gdouble grow, int which); -void sp_nodepath_flip (Inkscape::NodePath::Path *nodepath, NR::Dim2 axis); +void sp_nodepath_flip (Inkscape::NodePath::Path *nodepath, NR::Dim2 axis, NR::Maybe center); #endif diff --git a/src/seltrans.h b/src/seltrans.h index 74734cdd8..d3cbcbd57 100644 --- a/src/seltrans.h +++ b/src/seltrans.h @@ -18,6 +18,7 @@ #include #include #include +#include "knot.h" #include "forward.h" #include "selcue.h" #include "message-context.h" @@ -84,7 +85,10 @@ public: bool isGrabbed() { return _grabbed; } - + bool centerIsVisible() { + return ( _chandle && SP_KNOT_IS_VISIBLE (_chandle) ); + } + private: void _updateHandles(); void _updateVolatileState(); diff --git a/src/shape-editor.cpp b/src/shape-editor.cpp index d9eaf11bc..1a0f319da 100644 --- a/src/shape-editor.cpp +++ b/src/shape-editor.cpp @@ -412,9 +412,9 @@ void ShapeEditor::select_prev () { sp_nodepath_select_prev (this->nodepath); } -void ShapeEditor::flip (NR::Dim2 axis) { +void ShapeEditor::flip (NR::Dim2 axis, NR::Maybe center) { if (this->nodepath) - sp_nodepath_flip (this->nodepath, axis); + sp_nodepath_flip (this->nodepath, axis, center); } void ShapeEditor::distribute (NR::Dim2 axis) { diff --git a/src/shape-editor.h b/src/shape-editor.h index 37117331b..85837d105 100644 --- a/src/shape-editor.h +++ b/src/shape-editor.h @@ -22,6 +22,7 @@ class Path; #include "libnr/nr-path-code.h" #include "libnr/nr-point.h" +#include "libnr/nr-maybe.h" class SPKnotHolder; class SPDesktop; @@ -101,7 +102,7 @@ public: void select_next (); void select_prev (); - void flip (NR::Dim2 axis); + void flip (NR::Dim2 axis, NR::Maybe center = NR::Nothing()); void distribute (NR::Dim2 axis); void align (NR::Dim2 axis); diff --git a/src/verbs.cpp b/src/verbs.cpp index 977c22cf8..a7e39e38f 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -76,6 +76,8 @@ #include "sp-flowtext.h" #include "layer-fns.h" #include "node-context.h" +#include "select-context.h" +#include "seltrans.h" #include "gradient-context.h" #include "shape-editor.h" @@ -1262,7 +1264,13 @@ ObjectVerb::perform( SPAction *action, void *data, void *pdata ) if (!bbox) { return; } - NR::Point const center(bbox->midpoint()); + // If the rotation center of the selection is visible, choose it as reference point + // for horizontal and vertical flips. Otherwise, take the center of the bounding box. + NR::Point center; + if (tools_isactive(dt, TOOLS_SELECT) && sel->center() && SP_SELECT_CONTEXT(ec)->_seltrans->centerIsVisible()) + center = *sel->center(); + else + center = bbox->midpoint(); switch (reinterpret_cast(data)) { case SP_VERB_OBJECT_ROTATE_90_CW: @@ -1287,8 +1295,23 @@ ObjectVerb::perform( SPAction *action, void *data, void *pdata ) flowtext_to_text(); break; case SP_VERB_OBJECT_FLIP_HORIZONTAL: + // When working with the node tool ... if (tools_isactive(dt, TOOLS_NODES)) { - SP_NODE_CONTEXT(ec)->shape_editor->flip(NR::X); + Inkscape::NodePath::Node *active_node = Inkscape::NodePath::Path::active_node; + + // ... and one of the nodes is currently mouseovered ... + if (active_node) { + + // ... flip the selected nodes about that node + SP_NODE_CONTEXT(ec)->shape_editor->flip(NR::X, active_node->pos); + } else { + + // ... or else about the center of their bounding box. + SP_NODE_CONTEXT(ec)->shape_editor->flip(NR::X); + } + + // When working with the selector tool, flip the selection about its rotation center + // (if it is visible) or about the center of the bounding box. } else { sp_selection_scale_relative(sel, center, NR::scale(-1.0, 1.0)); } @@ -1296,8 +1319,14 @@ ObjectVerb::perform( SPAction *action, void *data, void *pdata ) _("Flip horizontally")); break; case SP_VERB_OBJECT_FLIP_VERTICAL: + // The behaviour is analogous to flipping horizontally if (tools_isactive(dt, TOOLS_NODES)) { - SP_NODE_CONTEXT(ec)->shape_editor->flip(NR::Y); + Inkscape::NodePath::Node *active_node = Inkscape::NodePath::Path::active_node; + if (active_node) { + SP_NODE_CONTEXT(ec)->shape_editor->flip(NR::Y, active_node->pos); + } else { + SP_NODE_CONTEXT(ec)->shape_editor->flip(NR::Y); + } } else { sp_selection_scale_relative(sel, center, NR::scale(1.0, -1.0)); } -- 2.30.2