Let a crop be trimmed from one edge
Four bar handles at the midpoints of the sides, each moving only its own side along the axis across it. The overlay reports an edge as 0.5 on the axis it does not move, so the anchor Rust takes is the middle of the far side. Under a ratio lock the dragged axis leads. with_aspect grew the short axis onto the ratio, which for an edge pulled inward made the untouched axis the leader and pushed the edge straight back out.
This commit is contained in:
@@ -1042,9 +1042,10 @@ fn wire_zoom_pan_crop(
|
||||
width,
|
||||
height,
|
||||
};
|
||||
// The overlay reports the corner it is *holding*; the point
|
||||
// that must not move is the opposite one. A move reports no
|
||||
// corner at all, and keeps the shape it already has — there is
|
||||
// The overlay reports the handle it is *holding*; the point
|
||||
// that must not move is the opposite one — the far corner, or
|
||||
// for an edge the middle of the far side. A move reports no
|
||||
// handle at all, and keeps the shape it already has — there is
|
||||
// nothing to reshape, and reshaping about a centre would drag
|
||||
// an over-moved rect smaller instead of sliding it along the
|
||||
// edge.
|
||||
|
||||
+61
-36
@@ -37,15 +37,17 @@ export component CropOverlay inherits Rectangle {
|
||||
in property <float> crop-w: 1.0;
|
||||
in property <float> crop-h: 1.0;
|
||||
|
||||
/// A dragged crop rect — `x`, `y`, `width`, `height`, then the corner the
|
||||
/// drag is holding as a `0`/`1` pair, or `-1, -1` where the whole rect is
|
||||
/// being moved and its shape must not be touched.
|
||||
/// A dragged crop rect — `x`, `y`, `width`, `height`, then the handle the
|
||||
/// drag is holding as a point of the rect: a `0`/`1` pair for a corner,
|
||||
/// `0.5` on the axis an edge does not move, or `-1, -1` where the whole
|
||||
/// rect is being moved and its shape must not be touched.
|
||||
///
|
||||
/// The corner is what an aspect lock needs and cannot infer: reshaping a
|
||||
/// rect onto a ratio has to know which of its corners is nailed down, and
|
||||
/// The handle is what an aspect lock needs and cannot infer: reshaping a
|
||||
/// rect onto a ratio has to know which point of it is nailed down, and
|
||||
/// only the handle that took the press knows that. It is reported as the
|
||||
/// held corner rather than as the fixed one because that is what is
|
||||
/// written here — Rust takes the opposite corner.
|
||||
/// held point rather than as the fixed one because that is what is
|
||||
/// written here — Rust takes the opposite one, which for an edge is the
|
||||
/// middle of the far side.
|
||||
callback crop-changed(float, float, float, float, float, float);
|
||||
|
||||
/// TRACES: FR-DEV-17
|
||||
@@ -189,24 +191,43 @@ export component CropOverlay inherits Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// Corner handles. Each drags one corner while the opposite
|
||||
// stays put, which is the only behaviour that lets a crop
|
||||
// be shaped rather than merely moved.
|
||||
for corner in [
|
||||
// Handles: the four edges, then the four corners.
|
||||
//
|
||||
// A corner drags one corner while the opposite stays put, which is the
|
||||
// only behaviour that lets a crop be shaped rather than merely moved. An
|
||||
// edge drags that one side along the axis across it and leaves the other
|
||||
// three where they are — the way to trim a strip off one side without
|
||||
// disturbing the corner you had already placed.
|
||||
//
|
||||
// Each is a point of the rect in its own `0..1` coordinates; `0.5` on an
|
||||
// axis is an edge's midpoint and means "this axis does not move". The
|
||||
// edges come first because among overlapping siblings the last declared
|
||||
// takes the press, and on a rect dragged small the corners are the ones
|
||||
// that must stay reachable.
|
||||
for handle in [
|
||||
{ hx: 0.5, hy: 0.0 },
|
||||
{ hx: 0.5, hy: 1.0 },
|
||||
{ hx: 0.0, hy: 0.5 },
|
||||
{ hx: 1.0, hy: 0.5 },
|
||||
{ hx: 0.0, hy: 0.0 },
|
||||
{ hx: 1.0, hy: 0.0 },
|
||||
{ hx: 0.0, hy: 1.0 },
|
||||
{ hx: 1.0, hy: 1.0 },
|
||||
]: Rectangle {
|
||||
property <length> size: 18px;
|
||||
x: parent.rx + corner.hx * parent.rw - self.size / 2;
|
||||
y: parent.ry + corner.hy * parent.rh - self.size / 2;
|
||||
width: self.size;
|
||||
height: self.size;
|
||||
property <bool> across: handle.hx == 0.5;
|
||||
property <bool> along: handle.hy == 0.5;
|
||||
// A corner is a square; an edge is a bar lying along its side, with
|
||||
// a hit area as long as the bar and as deep as a corner's.
|
||||
property <length> grip: 18px;
|
||||
property <length> reach: 36px;
|
||||
width: self.across ? self.reach : self.grip;
|
||||
height: self.along ? self.reach : self.grip;
|
||||
x: parent.rx + handle.hx * parent.rw - self.width / 2;
|
||||
y: parent.ry + handle.hy * parent.rh - self.height / 2;
|
||||
|
||||
Rectangle {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
width: parent.across ? 24px : (parent.along ? 5px : 12px);
|
||||
height: parent.along ? 24px : (parent.across ? 5px : 12px);
|
||||
background: #ffffff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
@@ -214,9 +235,13 @@ export component CropOverlay inherits Rectangle {
|
||||
TouchArea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
mouse-cursor: (corner.hx == corner.hy)
|
||||
? MouseCursor.nwse-resize
|
||||
: MouseCursor.nesw-resize;
|
||||
mouse-cursor: parent.across
|
||||
? MouseCursor.ns-resize
|
||||
: parent.along
|
||||
? MouseCursor.ew-resize
|
||||
: (handle.hx == handle.hy)
|
||||
? MouseCursor.nwse-resize
|
||||
: MouseCursor.nesw-resize;
|
||||
|
||||
property <float> ox;
|
||||
property <float> oy;
|
||||
@@ -246,27 +271,27 @@ export component CropOverlay inherits Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// Movement as a fraction of the frame, live while
|
||||
// the handle is held.
|
||||
property <float> dx: self.fraction-x(self.mouse-x) - self.from-x;
|
||||
property <float> dy: self.fraction-y(self.mouse-y) - self.from-y;
|
||||
// Movement as a fraction of the frame, live while the handle is
|
||||
// held — and nothing along an axis the handle does not move, so
|
||||
// an edge dragged at a slant still only moves its own side.
|
||||
property <float> dx: parent.across ? 0 : self.fraction-x(self.mouse-x) - self.from-x;
|
||||
property <float> dy: parent.along ? 0 : self.fraction-y(self.mouse-y) - self.from-y;
|
||||
|
||||
moved => {
|
||||
if (!self.pressed) {
|
||||
return;
|
||||
}
|
||||
// Dragging a left/top handle moves the origin
|
||||
// and shrinks the extent by the same amount;
|
||||
// a right/bottom handle moves only the extent.
|
||||
// Rust clamps the result, so an over-drag
|
||||
// slides rather than inverting.
|
||||
// Dragging a left/top handle moves the origin and shrinks the
|
||||
// extent by the same amount; a right/bottom handle moves only
|
||||
// the extent. Rust clamps the result, so an over-drag slides
|
||||
// rather than inverting.
|
||||
root.crop-changed(
|
||||
corner.hx == 0 ? self.ox + self.dx : self.ox,
|
||||
corner.hy == 0 ? self.oy + self.dy : self.oy,
|
||||
corner.hx == 0 ? self.ow - self.dx : self.ow + self.dx,
|
||||
corner.hy == 0 ? self.oh - self.dy : self.oh + self.dy,
|
||||
corner.hx,
|
||||
corner.hy,
|
||||
handle.hx == 0 ? self.ox + self.dx : self.ox,
|
||||
handle.hy == 0 ? self.oy + self.dy : self.oy,
|
||||
handle.hx == 0 ? self.ow - self.dx : self.ow + self.dx,
|
||||
handle.hy == 0 ? self.oh - self.dy : self.oh + self.dy,
|
||||
handle.hx,
|
||||
handle.hy,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user