Selection: size the window to the chip instead of masking a fullscreen shield
The masked-fullscreen version was completely untappable on device. Rather than keep guessing at the mask, the window is now sized to the card and moved by margins, so every pixel of it is the chip. Also stops an invisible fullscreen surface sitting over the app's own selection UI.
This commit is contained in:
parent
5a643d7059
commit
147f7f28b1
1 changed files with 30 additions and 32 deletions
|
|
@ -58,7 +58,18 @@ Scope {
|
|||
required property var modelData
|
||||
screen: win.modelData
|
||||
|
||||
anchors { top: true; left: true; right: true; bottom: true }
|
||||
// Sized to the card and positioned with margins, NOT a fullscreen
|
||||
// shield with an input mask. The masked-fullscreen version shipped
|
||||
// first and the chip was completely untappable on device; rather
|
||||
// than keep guessing at the mask, this removes the question — every
|
||||
// pixel of the window IS the chip, so there is nothing to mask and
|
||||
// no invisible surface over the rest of the screen to fight the
|
||||
// app's own selection UI (Firefox's popup, notably).
|
||||
anchors { top: true; left: true }
|
||||
margins { left: Math.round(win.targetX); top: Math.round(win.targetY) }
|
||||
implicitWidth: card.implicitWidth
|
||||
implicitHeight: card.implicitHeight
|
||||
|
||||
color: "transparent"
|
||||
visible: Selection.hasSelection
|
||||
WlrLayershell.namespace: "souveraine:selection"
|
||||
|
|
@ -66,30 +77,30 @@ Scope {
|
|||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
|
||||
// Only the card is interactive; the rest of the screen is not ours.
|
||||
mask: Region { item: card }
|
||||
|
||||
// Anchor. Selection gives a pointer hint, which is where the finger
|
||||
// lifted; -1 means it could not be resolved, and centre-bottom is
|
||||
// the thumb-reachable fallback. Clamped so the card is never partly
|
||||
// offscreen regardless of where the touch was.
|
||||
// Selection gives a pointer hint — where the finger lifted. -1 means
|
||||
// it could not be resolved, so fall back to thumb-reachable centre.
|
||||
// Clamped against the screen, not the window: the window is now the
|
||||
// card's size, so its own width/height cannot bound the placement.
|
||||
readonly property int pad: 12
|
||||
readonly property int hintX: Selection.anchorX
|
||||
readonly property int hintY: Selection.anchorY
|
||||
readonly property int scrW: win.screen ? win.screen.width : 1080
|
||||
readonly property int scrH: win.screen ? win.screen.height : 2160
|
||||
|
||||
readonly property real targetX: {
|
||||
if (win.hintX < 0) return (win.width - card.width) / 2;
|
||||
if (win.hintX < 0) return Math.max(win.pad, (win.scrW - card.implicitWidth) / 2);
|
||||
return Math.max(win.pad,
|
||||
Math.min(win.hintX - card.width / 2,
|
||||
win.width - card.width - win.pad));
|
||||
Math.min(win.hintX - card.implicitWidth / 2,
|
||||
win.scrW - card.implicitWidth - win.pad));
|
||||
}
|
||||
readonly property real targetY: {
|
||||
if (win.hintY < 0) return win.height * 0.72;
|
||||
// Prefer above the touch point so the finger does not cover the
|
||||
// menu; flip below when there is no room up there.
|
||||
const above = win.hintY - card.height - 16;
|
||||
if (win.hintY < 0) return win.scrH * 0.72;
|
||||
// Prefer above the touch point so the finger does not cover it;
|
||||
// flip below when there is no room up there.
|
||||
const above = win.hintY - card.implicitHeight - 16;
|
||||
if (above >= win.pad) return above;
|
||||
return Math.min(win.hintY + 16, win.height - card.height - win.pad);
|
||||
return Math.min(win.hintY + 16,
|
||||
win.scrH - card.implicitHeight - win.pad);
|
||||
}
|
||||
|
||||
// `card` takes its size from the layout's implicit size, and the
|
||||
|
|
@ -100,26 +111,13 @@ Scope {
|
|||
// chip painted but nothing could be tapped. The background stays a
|
||||
// plain Item child, because anchors on a layout-managed item are
|
||||
// undefined behavior.
|
||||
// The card fills the window now; the window's margins do the moving,
|
||||
// so there is no x/y to animate here.
|
||||
Item {
|
||||
id: card
|
||||
x: win.targetX
|
||||
y: win.targetY
|
||||
anchors.fill: parent
|
||||
implicitWidth: content.implicitWidth
|
||||
implicitHeight: content.implicitHeight
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
// Position eases so a re-selection slides rather than teleports,
|
||||
// but only once mapped — animating from 0,0 on first show reads
|
||||
// as the menu flying in from the corner.
|
||||
Behavior on x { enabled: card.opacity > 0; animation: Appearance.animation.elementMove.numberAnimation.createObject(this) }
|
||||
Behavior on y { enabled: card.opacity > 0; animation: Appearance.animation.elementMove.numberAnimation.createObject(this) }
|
||||
|
||||
opacity: Selection.hasSelection ? 1 : 0
|
||||
scale: Selection.hasSelection ? 1 : 0.88
|
||||
transformOrigin: Item.Bottom
|
||||
Behavior on opacity { NumberAnimation { duration: 120; easing.type: Easing.OutCubic } }
|
||||
Behavior on scale { animation: Appearance.animation.elementMove.numberAnimation.createObject(this) }
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
Loading…
Reference in a new issue