[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-kimageshop
Subject:    [graphics/krita] /: Fix inconvenient default shortcuts in the Mesh Transform tool
From:       Dmitry Kazakov <null () kde ! org>
Date:       2020-11-30 13:03:16
Message-ID: 20201130130316.2F45A1242E63 () leptone ! kde ! org
[Download RAW message or body]

Git commit 4b4b1f4ae6cabc86d3936348d7a26e0da0611505 by Dmitry Kazakov.
Committed on 30/11/2020 at 13:03.
Pushed by dkazakov into branch 'master'.

Fix inconvenient default shortcuts in the Mesh Transform tool

The patch bascially makes symmetric transforms be the default choice
available without any modifiers.

Now the shortcuts are the following:

1) Mesh node:
   - click+drag --- move node

2) Border node:
   - click+drag --- move node
   - shift+click+drag --- move whole row/column
   - ctrl+alt+click+drag --- split/slide row/column
   - ctrl+alt+click+drag-away --- remove split

3) Control point:
   - click+drag --- change control point symmetrically
   - shift+click+drag --- change control point non-symmetrically;
                          this action will create angular texture
                          artifacts
4) Node or Control:
   - ctrl+click --- select multiple nodes

5) Patch area:
   - click+drag --- free patch deform
   - shift+click+drag --- move whole mesh

6) Empty area outside mesh:
   - click+drag --- rotate mesh or selection
   - ctrl+click+drag --- scale mesh or selection
   - shift+click+drag --- move mesh or selection

CC:kimageshop@kde.org

M  +25   -11   libs/global/KisBezierMesh.h
M  +60   -29   plugins/tools/tool_transform2/kis_mesh_transform_strategy.cpp

https://invent.kde.org/graphics/krita/commit/4b4b1f4ae6cabc86d3936348d7a26e0da0611505

diff --git a/libs/global/KisBezierMesh.h b/libs/global/KisBezierMesh.h
index d23333fb1e..f31ff62a55 100644
--- a/libs/global/KisBezierMesh.h
+++ b/libs/global/KisBezierMesh.h
@@ -1305,11 +1305,17 @@ Mesh<NodeArg, \
PatchArg>::control_point_iterator_impl<is_const>::rightSegment() c  return \
SegmentIteratorType(m_mesh, m_col, m_row, true);  }
 
+enum SmartMoveMeshControlMode {
+    MoveFree,
+    MoveSymmetricLock,
+    MoveRotationLock
+};
+
 template<typename NodeArg, typename PatchArg>
 void smartMoveControl(Mesh<NodeArg, PatchArg> &mesh,
                       typename Mesh<NodeArg, PatchArg>::ControlPointIndex index,
                       const QPointF &move,
-                      bool lockNodes)
+                      SmartMoveMeshControlMode mode)
 {
     using ControlType = typename Mesh<NodeArg, PatchArg>::ControlType;
     using ControlPointIndex = typename Mesh<NodeArg, PatchArg>::ControlPointIndex;
@@ -1322,7 +1328,7 @@ void smartMoveControl(Mesh<NodeArg, PatchArg> &mesh,
     } else {
         const QPointF newPos = *it + move;
 
-        if (lockNodes) {
+        if (mode == MoveRotationLock || mode == MoveSymmetricLock) {
             const qreal rotation = KisAlgebra2D::angleBetweenVectors(*it - \
                it.node().node,
                                                                      newPos - \
it.node().node);  QTransform R;
@@ -1333,19 +1339,26 @@ void smartMoveControl(Mesh<NodeArg, PatchArg> &mesh,
                     R *
                     QTransform::fromTranslate(it.node().node.x(), \
it.node().node.y());  
-            for (int intType = 0; intType < 4; intType++) {
-                ControlType type = static_cast<ControlType>(intType);
+            if (mode == MoveRotationLock) {
+                for (int intType = 0; intType < 4; intType++) {
+                    ControlType type = static_cast<ControlType>(intType);
 
-                if (type == ControlType::Node ||
-                    type == index.controlType) {
+                    if (type == ControlType::Node ||
+                            type == index.controlType) {
 
-                    continue;
-                }
+                        continue;
+                    }
 
-                auto neighbourIt = mesh.find(ControlPointIndex(index.nodeIndex, \
                type));
-                if (neighbourIt == mesh.endControlPoints()) continue;
+                    auto neighbourIt = mesh.find(ControlPointIndex(index.nodeIndex, \
type)); +                    if (neighbourIt == mesh.endControlPoints()) continue;
 
-                *neighbourIt = t.map(*neighbourIt);
+                    *neighbourIt = t.map(*neighbourIt);
+                }
+            } else {
+                auto neighbourIt = it.symmetricControl();
+                if (neighbourIt != mesh.endControlPoints()) {
+                    *neighbourIt = t.map(*neighbourIt);
+                }
             }
         }
 
@@ -1372,6 +1385,7 @@ using KisBezierMeshDetails::saveValue;
 template <typename Node, typename Patch>
 using KisBezierMeshBase = KisBezierMeshDetails::Mesh<Node, Patch>;
 
+using KisSmartMoveMeshControlMode = KisBezierMeshDetails::SmartMoveMeshControlMode;
 using KisBezierMesh = KisBezierMeshDetails::Mesh<KisBezierMeshDetails::BaseMeshNode, \
KisBezierPatch>;  
 
diff --git a/plugins/tools/tool_transform2/kis_mesh_transform_strategy.cpp \
b/plugins/tools/tool_transform2/kis_mesh_transform_strategy.cpp index \
                2c8d738d57..5cd3b6dbf7 100644
--- a/plugins/tools/tool_transform2/kis_mesh_transform_strategy.cpp
+++ b/plugins/tools/tool_transform2/kis_mesh_transform_strategy.cpp
@@ -43,6 +43,8 @@ struct KisMeshTransformStrategy::Private
     enum Mode {
         OVER_POINT = 0,
         OVER_POINT_SYMMETRIC,
+        OVER_NODE,
+        OVER_NODE_WHOLE_LINE,
         OVER_SEGMENT,
         OVER_SEGMENT_SYMMETRIC,
         OVER_PATCH,
@@ -122,15 +124,19 @@ void KisMeshTransformStrategy::setTransformFunction(const \
                QPointF &mousePos, boo
         auto index = m_d->currentArgs.meshTransform()->hitTestControlPoint(mousePos, \
grabRadius);  if (m_d->currentArgs.meshTransform()->isIndexValid(index)) {
             hoveredControl = index;
-            mode = Private::OVER_POINT;
+            mode = !shiftModifierActive ? Private::OVER_POINT_SYMMETRIC : \
Private::OVER_POINT;  }
     }
 
     if (mode == Private::NOTHING) {
         auto index = m_d->currentArgs.meshTransform()->hitTestNode(mousePos, \
                grabRadius);
-        if (m_d->currentArgs.meshTransform()->isIndexValid(index)) {
+        auto nodeIt = m_d->currentArgs.meshTransform()->find(index);
+
+        if (nodeIt != m_d->currentArgs.meshTransform()->endControlPoints()) {
             hoveredControl = index;
-            mode = Private::OVER_POINT;
+            mode = shiftModifierActive && nodeIt.isBorderNode() && \
!nodeIt.isCornerNode() ? +                Private::OVER_NODE_WHOLE_LINE :
+                Private::OVER_NODE;
         }
     }
 
@@ -138,7 +144,7 @@ void KisMeshTransformStrategy::setTransformFunction(const QPointF \
                &mousePos, boo
         auto index = m_d->currentArgs.meshTransform()->hitTestSegment(mousePos, \
grabRadius, &localSegmentPos);  if \
(m_d->currentArgs.meshTransform()->isIndexValid(index)) {  hoveredSegment = index;
-            mode = Private::OVER_SEGMENT;
+            mode = !shiftModifierActive ? Private::OVER_SEGMENT_SYMMETRIC : \
Private::OVER_SEGMENT;  }
     }
 
@@ -146,7 +152,7 @@ void KisMeshTransformStrategy::setTransformFunction(const QPointF \
                &mousePos, boo
         auto index = m_d->currentArgs.meshTransform()->hitTestPatch(mousePos, \
&localPatchPos);  if (m_d->currentArgs.meshTransform()->isIndexValid(index)) {
             hoveredPatch = index;
-            mode = Private::OVER_PATCH;
+            mode = !shiftModifierActive ? Private::OVER_PATCH : Private::MOVE_MODE;
         }
     }
 
@@ -173,13 +179,6 @@ void KisMeshTransformStrategy::setTransformFunction(const \
QPointF &mousePos, boo  
         mode = Private::SPLIT_SEGMENT;
 
-    } else if (shiftModifierActive &&
-               hoveredControl &&
-               !hoveredControl->isNode()) {
-        mode = Private::OVER_POINT_SYMMETRIC;
-    } else if (shiftModifierActive &&
-               hoveredSegment) {
-        mode = Private::OVER_SEGMENT_SYMMETRIC;
     } else {
         if (hoveredControl || hoveredSegment) {
             if (perspectiveModifierActive) {
@@ -190,13 +189,12 @@ void KisMeshTransformStrategy::setTransformFunction(const \
                QPointF &mousePos, boo
                        m_d->selectedNodes.contains(hoveredControl->nodeIndex)) {
 
                 mode = Private::MOVE_MODE;
-
             }
-        } else {
-            if (hoveredPatch) {
-                mode = shiftModifierActive ? Private::OVER_PATCH : \
                Private::MOVE_MODE;
-            } else if (perspectiveModifierActive) {
+        } else if (!hoveredPatch) {
+            if (perspectiveModifierActive) {
                 mode = Private::SCALE_MODE;
+            } else if (shiftModifierActive) {
+                mode = Private::MOVE_MODE;
             } else {
                 mode = Private::ROTATE_MODE;
             }
@@ -303,10 +301,12 @@ QCursor KisMeshTransformStrategy::getCurrentCursor() const
     QCursor cursor;
 
     switch (m_d->mode) {
+    case Private::OVER_NODE:
     case Private::OVER_POINT:
     case Private::OVER_SEGMENT:
         cursor = KisCursor::meshCursorFree();
         break;
+    case Private::OVER_NODE_WHOLE_LINE:
     case Private::OVER_POINT_SYMMETRIC:
     case Private::OVER_SEGMENT_SYMMETRIC:
     case Private::OVER_PATCH:
@@ -467,7 +467,9 @@ bool KisMeshTransformStrategy::beginPrimaryAction(const QPointF \
&pt)  
     m_d->pointWasDragged = false;
 
-    if (m_d->mode == Private::OVER_POINT || m_d->mode == \
Private::OVER_POINT_SYMMETRIC) { +    if (m_d->mode == Private::OVER_NODE ||
+        m_d->mode == Private::OVER_POINT ||
+        m_d->mode == Private::OVER_POINT_SYMMETRIC) {
         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->hoveredControl, false);
 
         if (m_d->selectedNodes.size() <= 1 ||
@@ -478,7 +480,21 @@ bool KisMeshTransformStrategy::beginPrimaryAction(const QPointF \
&pt)  }
 
         retval = true;
+    } else if (m_d->mode == Private::OVER_NODE_WHOLE_LINE) {
+        m_d->selectedNodes.clear();
+        auto it = m_d->currentArgs.meshTransform()->find(*m_d->hoveredControl);
+        KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(it != \
m_d->currentArgs.meshTransform()->endControlPoints(), false);  
+        if (it.isTopBorder() || it.isBottomBorder()) {
+            for (int i = 0; i < m_d->currentArgs.meshTransform()->size().height(); \
i++) { +                m_d->selectedNodes << \
KisBezierTransformMesh::NodeIndex(m_d->hoveredControl->nodeIndex.x(), i); +           \
} +        } else {
+            for (int i = 0; i < m_d->currentArgs.meshTransform()->size().width(); \
i++) { +                m_d->selectedNodes << KisBezierTransformMesh::NodeIndex(i, \
m_d->hoveredControl->nodeIndex.y()); +            }
+        }
+        retval = true;
     } else if (m_d->mode == Private::OVER_SEGMENT || m_d->mode == \
Private::OVER_SEGMENT_SYMMETRIC) {  \
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_d->hoveredSegment, false);  
@@ -531,13 +547,21 @@ void KisMeshTransformStrategy::continuePrimaryAction(const \
QPointF &pt, bool shi  Q_UNUSED(shiftModifierActve);
     Q_UNUSED(altModifierActive);
 
-    if (m_d->mode == Private::OVER_POINT || m_d->mode == \
Private::OVER_POINT_SYMMETRIC) { +    if (m_d->mode == Private::OVER_POINT ||
+        m_d->mode == Private::OVER_POINT_SYMMETRIC ||
+        m_d->mode == Private::OVER_NODE) {
+
         KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->hoveredControl);
 
+        KisSmartMoveMeshControlMode mode =
+            m_d->mode == Private::OVER_POINT_SYMMETRIC ?
+            KisSmartMoveMeshControlMode::MoveSymmetricLock :
+            KisSmartMoveMeshControlMode::MoveFree;
+
         smartMoveControl(*m_d->currentArgs.meshTransform(),
                          *m_d->hoveredControl,
                          pt - m_d->lastMousePos,
-                         m_d->mode == Private::OVER_POINT_SYMMETRIC);
+                         mode);
 
     } else if (m_d->mode == Private::OVER_SEGMENT || m_d->mode == \
Private::OVER_SEGMENT_SYMMETRIC) {  \
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->hoveredSegment); @@ -556,8 +580,14 @@ void \
KisMeshTransformStrategy::continuePrimaryAction(const QPointF &pt, bool shi  \
                std::tie(offsetP1, offsetP2) =
             KisBezierUtils::offsetSegment(m_d->localSegmentPosition, offset);
 
-        smartMoveControl(*m_d->currentArgs.meshTransform(), \
                it.itP1().controlIndex(), offsetP1, m_d->mode == \
                Private::OVER_SEGMENT_SYMMETRIC);
-        smartMoveControl(*m_d->currentArgs.meshTransform(), \
it.itP2().controlIndex(), offsetP2, m_d->mode == Private::OVER_SEGMENT_SYMMETRIC); +
+        KisSmartMoveMeshControlMode mode =
+            m_d->mode == Private::OVER_SEGMENT_SYMMETRIC ?
+            KisSmartMoveMeshControlMode::MoveSymmetricLock :
+            KisSmartMoveMeshControlMode::MoveFree;
+
+        smartMoveControl(*m_d->currentArgs.meshTransform(), \
it.itP1().controlIndex(), offsetP1, mode); +        \
smartMoveControl(*m_d->currentArgs.meshTransform(), it.itP2().controlIndex(), \
offsetP2, mode);  
     } else if (m_d->mode == Private::OVER_PATCH) {
         KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->hoveredPatch);
@@ -569,10 +599,10 @@ void KisMeshTransformStrategy::continuePrimaryAction(const \
QPointF &pt, bool shi  const QPointF offset = pt - m_d->mouseClickPos;
 
         auto offsetSegment =
-            [] (KisBezierTransformMesh::segment_iterator it,
-                qreal t,
-                qreal distance,
-                const QPointF &offset) {
+            [this] (KisBezierTransformMesh::segment_iterator it,
+                    qreal t,
+                    qreal distance,
+                    const QPointF &offset) {
 
             QPointF offsetP1;
             QPointF offsetP2;
@@ -580,8 +610,9 @@ void KisMeshTransformStrategy::continuePrimaryAction(const \
QPointF &pt, bool shi  std::tie(offsetP1, offsetP2) =
                 KisBezierUtils::offsetSegment(t, (1.0 - distance) * offset);
 
-            it.p1() += offsetP1;
-            it.p2() += offsetP2;
+
+            smartMoveControl(*m_d->currentArgs.meshTransform(), \
it.itP1().controlIndex(), offsetP1, KisSmartMoveMeshControlMode::MoveSymmetricLock); \
+            smartMoveControl(*m_d->currentArgs.meshTransform(), \
it.itP2().controlIndex(), offsetP2, KisSmartMoveMeshControlMode::MoveSymmetricLock);  \
};  
         offsetSegment(patchIt.segmentP(), m_d->localPatchPosition.x(), \
m_d->localPatchPosition.y(), offset); @@ -594,7 +625,7 @@ void \
KisMeshTransformStrategy::continuePrimaryAction(const QPointF &pt, bool shi  const \
bool sanitySplitResult = splitHoveredSegment(pt);  \
KIS_SAFE_ASSERT_RECOVER_NOOP(sanitySplitResult);  
-    } else if (m_d->mode == Private::MOVE_MODE) {
+    } else if (m_d->mode == Private::MOVE_MODE || m_d->mode == \
Private::OVER_NODE_WHOLE_LINE) {  const QPointF offset = pt - m_d->lastMousePos;
         if (m_d->selectedNodes.size() > 1) {
             for (auto it = m_d->selectedNodes.begin(); it != \
m_d->selectedNodes.end(); ++it) {


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic