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

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

Git commit 40f8c1689c3809bd098fbf4a2b3cd35d65db97af by Dmitry Kazakov.
Committed on 30/11/2020 at 12:53.
Pushed by dkazakov into branch 'krita/4.3'.

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/40f8c1689c3809bd098fbf4a2b3cd35d65db97af

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 \
                bfe95f5285..b3d593de06 100644
--- a/plugins/tools/tool_transform2/kis_mesh_transform_strategy.cpp
+++ b/plugins/tools/tool_transform2/kis_mesh_transform_strategy.cpp
@@ -55,6 +55,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,
@@ -134,15 +136,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;
         }
     }
 
@@ -150,7 +156,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;  }
     }
 
@@ -158,7 +164,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;
         }
     }
 
@@ -185,13 +191,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) {
@@ -202,13 +201,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;
             }
@@ -315,10 +313,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:
@@ -479,7 +479,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 ||
@@ -490,7 +492,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);  
@@ -543,13 +559,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); @@ -568,8 +592,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);
@@ -581,10 +611,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;
@@ -592,8 +622,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); @@ -606,7 +637,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