Code

flipping patch by maximilian albert
authorbuliabyak <buliabyak@users.sourceforge.net>
Tue, 17 Apr 2007 20:57:57 +0000 (20:57 +0000)
committerbuliabyak <buliabyak@users.sourceforge.net>
Tue, 17 Apr 2007 20:57:57 +0000 (20:57 +0000)
src/nodepath.cpp
src/nodepath.h
src/seltrans.h
src/shape-editor.cpp
src/shape-editor.h
src/verbs.cpp

index 32e302e330ad1fd7b3b7321f84f49c9f6f4ca5ca..0ad4c66a030c190776b9c53cc158dd6c1ea7ae5e 100644 (file)
@@ -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<NR::Point> 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;
index 46d768b6315db85975cbd49899c6b176ea852369..967650818764710eb0d6089b5b616a0c18206db4 100644 (file)
@@ -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<NR::Point> center);
 
 #endif
index 74734cdd876e6189e20efddc8a1a22973380b3b8..d3cbcbd5750861cfb3210631a3aeeaf43443cf0e 100644 (file)
@@ -18,6 +18,7 @@
 #include <libnr/nr-point.h>
 #include <libnr/nr-matrix.h>
 #include <libnr/nr-rect.h>
+#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();
index d9eaf11bc83bebf347bdf20ff6e9d1b789c1e4c4..1a0f319da0b362ea1bc027051e70d63e6bcf27a8 100644 (file)
@@ -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<NR::Point> center) {
     if (this->nodepath) 
-        sp_nodepath_flip (this->nodepath, axis);
+        sp_nodepath_flip (this->nodepath, axis, center);
 }
 
 void ShapeEditor::distribute (NR::Dim2 axis) {
index 37117331bf8d8e572879af0b17bf7aaabfb13068..85837d10558cdf2cf3d489a60cc9735364fad04d 100644 (file)
@@ -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<NR::Point> center = NR::Nothing());
 
     void distribute (NR::Dim2 axis);
     void align (NR::Dim2 axis);
index 977c22cf8a1de84bd5b987f6ec152e7226c34172..a7e39e38fda5859f40366990e49081a688a7e716 100644 (file)
@@ -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<std::size_t>(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));
             }