[graphics/krita/krita/4.3] /: Fix inconvenient default shortcuts in the Mesh Transform tool
Dmitry Kazakov
null at kde.org
Mon Nov 30 13:02:34 GMT 2020
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 at 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) {
More information about the kimageshop
mailing list