The Marquee, shapes and a moved selection snap to View › Snap To; Ctrl draws freely (13.5a)
This commit is contained in:
1 parent
64ebd1cdf9
commit
3992bc913d
11 files changed
+271
-11
No files matched your search
@@ -3,6 +3,10 @@ public:
|
||||
SnapGuides transformSnapTargets(const QSet<QUuid> &moving) const;
|
||||
LayerTransform snappedMove(const LayerTransform &draft, const QSet<QUuid> &moving, double tolerance);
|
||||
SnapGuides cropSnapTargets() const;
|
||||
// A drawn corner, each axis to a target within reach.
|
||||
QPointF snappedPoint(QPointF point, double tolerance);
|
||||
// A moved selection's edges or middle; a locked axis stays.
|
||||
QSizeF snappedSelectionOffset(QSizeF offset, double tolerance, bool horizontal = true, bool vertical = true);
|
||||
// The Crop tool's frame: the canvas until one is drawn.
|
||||
std::optional<QRectF> visibleCropRect() const;
|
||||
std::optional<double> cropRatio() const;
|
||||
|
||||
@@ -174,6 +174,41 @@ SnapGuides EditorSession::cropSnapTargets() const
|
||||
return alignmentSnapTargets({}, false);
|
||||
}
|
||||
|
||||
QPointF EditorSession::snappedPoint(QPointF point, double tolerance)
|
||||
{
|
||||
if (!m_snappingEnabled) {
|
||||
snapGuides = {};
|
||||
return point;
|
||||
}
|
||||
const SnapGuides targets = cropSnapTargets();
|
||||
// The first of the nearest, as Swift's `min`.
|
||||
const auto nearest = [tolerance](double value, const std::vector<double> &lines) {
|
||||
std::optional<double> best;
|
||||
for (const double line : lines)
|
||||
if (std::abs(line - value) <= tolerance && (!best || std::abs(line - value) < std::abs(*best - value)))
|
||||
best = line;
|
||||
return best;
|
||||
};
|
||||
const std::optional<double> x = nearest(point.x(), targets.xs), y = nearest(point.y(), targets.ys);
|
||||
snapGuides = {x ? std::vector<double>{*x} : std::vector<double>{}, y ? std::vector<double>{*y} : std::vector<double>{}};
|
||||
return QPointF(x.value_or(point.x()), y.value_or(point.y()));
|
||||
}
|
||||
|
||||
QSizeF EditorSession::snappedSelectionOffset(QSizeF offset, double tolerance, bool horizontal, bool vertical)
|
||||
{
|
||||
if (!m_snappingEnabled || !m_selectionMoveOrigin) {
|
||||
snapGuides = {};
|
||||
return offset;
|
||||
}
|
||||
const QSizeF whole(std::round(offset.width()), std::round(offset.height()));
|
||||
const QRectF box = m_selectionMoveOrigin->path.boundingRect().translated(whole.width(), whole.height());
|
||||
const SnapGuides targets = cropSnapTargets();
|
||||
const TransformSnap::Offset snap =
|
||||
TransformSnap::offset(box, horizontal ? targets.xs : std::vector<double>{}, vertical ? targets.ys : std::vector<double>{}, tolerance);
|
||||
snapGuides = {snap.x ? std::vector<double>{*snap.x} : std::vector<double>{}, snap.y ? std::vector<double>{*snap.y} : std::vector<double>{}};
|
||||
return whole + snap.offset;
|
||||
}
|
||||
|
||||
std::optional<QRectF> EditorSession::visibleCropRect() const
|
||||
{
|
||||
if (m_tool != NavigationTool::crop || !m_document)
|
||||
|
||||
@@ -183,7 +183,7 @@ void CanvasView::press(QMouseEvent *event, int clicks)
|
||||
} else if (m_session.tool() == NavigationTool::gradient) {
|
||||
beginGradientDrag(point);
|
||||
} else if (m_session.tool() == NavigationTool::shape) {
|
||||
m_session.beginShape(m_session.viewport.documentPoint(point, m_session.document()->size()));
|
||||
m_session.beginShape(snappedCorner(m_session.viewport.documentPoint(point, m_session.document()->size()), event->modifiers()));
|
||||
} else if (m_session.tool() == NavigationTool::crop) {
|
||||
beginCropDrag(point);
|
||||
} else if (m_session.tool() == NavigationTool::type) {
|
||||
@@ -271,7 +271,7 @@ void CanvasView::mouseMoveEvent(QMouseEvent *event)
|
||||
return;
|
||||
if (m_session.shapeDraft() && m_session.document()) {
|
||||
// Alt has no other job here: it grows from centre.
|
||||
m_session.dragShape(m_session.viewport.documentPoint(point, m_session.document()->size()),
|
||||
m_session.dragShape(snappedCorner(m_session.viewport.documentPoint(point, m_session.document()->size()), event->modifiers()),
|
||||
event->modifiers().testFlag(Qt::ShiftModifier), event->modifiers().testFlag(Qt::AltModifier));
|
||||
synchronizeDisplay();
|
||||
return;
|
||||
|
||||
@@ -67,7 +67,7 @@ void CanvasView::lassoMouseDown(QPointF point, Qt::KeyboardModifiers modifiers)
|
||||
m_session.magicWand(pixel, mode);
|
||||
return;
|
||||
}
|
||||
m_session.beginLasso(pixel, mode);
|
||||
m_session.beginLasso(m_session.tool() == NavigationTool::marquee ? snappedCorner(pixel, modifiers) : pixel, mode);
|
||||
synchronizeDisplay();
|
||||
return;
|
||||
}
|
||||
@@ -218,22 +218,41 @@ void CanvasView::dragSelection(QPointF point, Qt::KeyboardModifiers modifiers)
|
||||
return;
|
||||
const QPointF pixel = m_session.viewport.documentPoint(point, m_session.document()->size());
|
||||
QSizeF offset(pixel.x() - m_selectionDragStart->x(), pixel.y() - m_selectionDragStart->y());
|
||||
bool horizontal = true, vertical = true;
|
||||
if (modifiers.testFlag(Qt::ShiftModifier)) {
|
||||
if (std::abs(offset.width()) >= std::abs(offset.height()))
|
||||
if (std::abs(offset.width()) >= std::abs(offset.height())) {
|
||||
offset.setHeight(0);
|
||||
else
|
||||
vertical = false;
|
||||
} else {
|
||||
offset.setWidth(0);
|
||||
horizontal = false;
|
||||
}
|
||||
}
|
||||
// Snaps as a drawn Marquee does, unless Ctrl is held.
|
||||
if (modifiers.testFlag(Qt::ControlModifier))
|
||||
m_session.snapGuides = {};
|
||||
else
|
||||
offset = m_session.snappedSelectionOffset(offset, TransformSnap::distance / std::max(m_session.viewport.pointsPerPixel(), 0.0001), horizontal,
|
||||
vertical);
|
||||
m_session.moveSelection(offset);
|
||||
}
|
||||
|
||||
QPointF CanvasView::snappedCorner(QPointF pixel, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (modifiers.testFlag(Qt::ControlModifier)) {
|
||||
m_session.snapGuides = {};
|
||||
return pixel;
|
||||
}
|
||||
return m_session.snappedPoint(pixel, TransformSnap::distance / std::max(m_session.viewport.pointsPerPixel(), 0.0001));
|
||||
}
|
||||
|
||||
// Alt subtracts, never from the centre; Shift squares once armed.
|
||||
void CanvasView::dragMarqueeDraft(QPointF pixel, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!modifiers.testFlag(Qt::ShiftModifier))
|
||||
m_marqueeConstrainArmed = true;
|
||||
m_marqueeDragPixel = pixel;
|
||||
m_session.dragMarquee(pixel, m_marqueeConstrainArmed && modifiers.testFlag(Qt::ShiftModifier), false);
|
||||
m_session.dragMarquee(snappedCorner(pixel, modifiers), m_marqueeConstrainArmed && modifiers.testFlag(Qt::ShiftModifier), false);
|
||||
}
|
||||
|
||||
// A frame's pan toward a pointer at the edge.
|
||||
|
||||
@@ -210,6 +210,8 @@ private:
|
||||
void endSelectionGestures();
|
||||
void dragSelection(QPointF point, Qt::KeyboardModifiers modifiers);
|
||||
void dragMarqueeDraft(QPointF pixel, Qt::KeyboardModifiers modifiers);
|
||||
// A Marquee or shape corner, snapped unless Ctrl is held.
|
||||
QPointF snappedCorner(QPointF pixel, Qt::KeyboardModifiers modifiers);
|
||||
QSizeF marqueeAutoscrollDelta(QPointF point) const;
|
||||
void updateMarqueeAutoscroll(QPointF point);
|
||||
void stepMarqueeAutoscroll();
|
||||
|
||||
Reference in new issue
Block a user