mirror of
https://github.com/thesleepingsage/hypr-lens.git
synced 2026-11-01 06:56:42 +01:00
fix(regionSelector): Freehand->Rect auto-swap fires at Crop entry, not exit
The swap in onCaptureModeChanged read isCropMode - a derived binding that may not have re-evaluated inside the handler - so it skipped at entry (stale false) and fired at exit (stale true), leaving the tab oval on Freehand for the whole Crop session. Read captureMode directly. Also hardened while diagnosing: ToolbarTabBar indicator binds its edge targets directly to children[currentIndex] (drops the property Item hop), and gains an interactive property so callers dim via opacity instead of enabled: false.
This commit is contained in:
1 parent
3bbfdbb6bf
commit
ef737f5992
3 files changed
+27
-11
No files matched your search
@@ -10,6 +10,10 @@ Item {
|
||||
id: root
|
||||
property alias currentIndex: tabBar.currentIndex
|
||||
required property var tabButtonList
|
||||
// Gate user input without `enabled: false` — disabling the bar stalls the
|
||||
// active-indicator animation until re-enable (the oval visually sticks on the
|
||||
// old tab). Callers dim via opacity and set interactive: false instead.
|
||||
property bool interactive: true
|
||||
|
||||
function incrementCurrentIndex() {
|
||||
tabBar.incrementCurrentIndex()
|
||||
@@ -40,12 +44,13 @@ Item {
|
||||
text: modelData.name
|
||||
materialSymbol: modelData.icon
|
||||
onClicked: {
|
||||
root.setCurrentIndex(index)
|
||||
if (root.interactive) root.setCurrentIndex(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: activeIndicator
|
||||
z: 0
|
||||
@@ -53,19 +58,24 @@ Item {
|
||||
implicitWidth: contentItem.children[root.currentIndex]?.implicitWidth ?? 0
|
||||
implicitHeight: contentItem.children[root.currentIndex]?.implicitHeight ?? 0
|
||||
radius: height / 2
|
||||
// Animation
|
||||
property Item targetItem: contentItem.children[root.currentIndex]
|
||||
// Animation. Bind the edge targets straight to the children/currentIndex
|
||||
// expression — an intermediate `property Item targetItem` hop silently failed
|
||||
// to re-fire the pair's index binding on programmatic index changes, leaving
|
||||
// the indicator stranded on the old tab.
|
||||
readonly property real targetX: contentItem.children[root.currentIndex]?.x ?? 0
|
||||
readonly property real targetRight: (contentItem.children[root.currentIndex]?.x ?? 0)
|
||||
+ (contentItem.children[root.currentIndex]?.width ?? 0)
|
||||
AnimatedTabIndexPair {
|
||||
id: leftBound
|
||||
idx1Duration: 50
|
||||
idx2Duration: 200
|
||||
index: activeIndicator.targetItem.x
|
||||
index: activeIndicator.targetX
|
||||
}
|
||||
AnimatedTabIndexPair {
|
||||
id: rightBound
|
||||
idx1Duration: 50
|
||||
idx2Duration: 200
|
||||
index: activeIndicator.targetItem.x + activeIndicator.targetItem.width
|
||||
index: activeIndicator.targetRight
|
||||
}
|
||||
x: Math.min(leftBound.idx1, leftBound.idx2)
|
||||
width: Math.max(rightBound.idx1, rightBound.idx2) - x
|
||||
@@ -77,6 +87,7 @@ Item {
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onWheel: (event) => {
|
||||
if (!root.interactive) return;
|
||||
if (event.angleDelta.y < 0) {
|
||||
root.incrementCurrentIndex();
|
||||
}
|
||||
|
||||
@@ -76,11 +76,12 @@ Toolbar {
|
||||
}
|
||||
|
||||
// Selection mode tabs (Rect/Freehand) - inert while Crop is active (Crop implies
|
||||
// rectangles; entering Crop from Freehand auto-swaps to Rect)
|
||||
// rectangles; entering Crop from Freehand auto-swaps to Rect). Dimmed via opacity +
|
||||
// interactive, NOT enabled — see ToolbarTabBar.interactive.
|
||||
ToolbarTabBar {
|
||||
id: tabBar
|
||||
enabled: !root.cropActive
|
||||
opacity: enabled ? 1 : 0.4
|
||||
interactive: !root.cropActive
|
||||
opacity: interactive ? 1 : 0.4
|
||||
tabButtonList: [
|
||||
{"icon": "activity_zone", "name": Translation.tr("Rect")},
|
||||
{"icon": "gesture", "name": Translation.tr("Freehand")}
|
||||
@@ -101,8 +102,8 @@ Toolbar {
|
||||
// (Esc, C and the FABs are the editor exits)
|
||||
ToolbarTabBar {
|
||||
id: captureModeTabBar
|
||||
enabled: !root.cropEditing
|
||||
opacity: enabled ? 1 : 0.4
|
||||
interactive: !root.cropEditing
|
||||
opacity: interactive ? 1 : 0.4
|
||||
tabButtonList: [
|
||||
{"icon": "bolt", "name": Translation.tr("Instant")},
|
||||
{"icon": "crop", "name": Translation.tr("Crop")}
|
||||
|
||||
@@ -54,7 +54,11 @@ PanelWindow {
|
||||
root.cropEditing = false;
|
||||
root.pendingSnipPoints = [];
|
||||
dragState.reset();
|
||||
if (root.isCropMode && root.selectionMode === RegionSelection.SelectionMode.Circle) {
|
||||
// Read captureMode directly, NOT isCropMode: the derived binding may not have
|
||||
// re-evaluated yet inside this handler (stale read = the swap fires one toggle
|
||||
// late, on exit instead of entry)
|
||||
if (root.captureMode === RegionSelection.CaptureMode.Crop
|
||||
&& root.selectionMode === RegionSelection.SelectionMode.Circle) {
|
||||
root.selectionMode = RegionSelection.SelectionMode.RectCorners;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user