mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
SessionMenu: ignore initial mouse position (similar to laucnher) - allow for a better keyboard centric experience
This commit is contained in:
@@ -63,6 +63,23 @@ SmartPanel {
|
||||
|
||||
// Navigation properties
|
||||
property int selectedIndex: -1
|
||||
property bool ignoreMouseHover: true // Transient flag, should always be true on init
|
||||
|
||||
// Global mouse tracking for movement detection across delegates
|
||||
property real globalLastMouseX: 0
|
||||
property real globalLastMouseY: 0
|
||||
property bool globalMouseInitialized: false
|
||||
property bool mouseTrackingReady: false // Delay tracking until panel is settled
|
||||
|
||||
Timer {
|
||||
id: mouseTrackingDelayTimer
|
||||
interval: Style.animationNormal + 50 // Wait for panel animation to complete + safety margin
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
root.mouseTrackingReady = true;
|
||||
root.globalMouseInitialized = false; // Reset so we get fresh initial position
|
||||
}
|
||||
}
|
||||
|
||||
// Action metadata mapping
|
||||
readonly property var actionMetadata: {
|
||||
@@ -135,11 +152,16 @@ SmartPanel {
|
||||
// Lifecycle handlers
|
||||
onOpened: {
|
||||
selectedIndex = -1;
|
||||
ignoreMouseHover = true;
|
||||
globalMouseInitialized = false;
|
||||
mouseTrackingReady = false;
|
||||
mouseTrackingDelayTimer.restart();
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
cancelTimer();
|
||||
selectedIndex = -1;
|
||||
ignoreMouseHover = true;
|
||||
}
|
||||
|
||||
// Timer management
|
||||
@@ -455,6 +477,31 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: globalHoverHandler
|
||||
|
||||
onPointChanged: {
|
||||
if (!root.mouseTrackingReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!root.globalMouseInitialized) {
|
||||
root.globalLastMouseX = point.position.x;
|
||||
root.globalLastMouseY = point.position.y;
|
||||
root.globalMouseInitialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const deltaX = Math.abs(point.position.x - root.globalLastMouseX);
|
||||
const deltaY = Math.abs(point.position.y - root.globalLastMouseY);
|
||||
if (deltaX + deltaY >= 5) {
|
||||
root.ignoreMouseHover = false;
|
||||
root.globalLastMouseX = point.position.x;
|
||||
root.globalLastMouseY = point.position.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Timer text for large buttons style (above buttons) - positioned absolutely with background
|
||||
Rectangle {
|
||||
id: timerTextContainer
|
||||
@@ -509,6 +556,7 @@ SmartPanel {
|
||||
isShutdown: modelData.isShutdown || false
|
||||
isSelected: index === selectedIndex
|
||||
number: index + 1
|
||||
buttonIndex: index
|
||||
onClicked: {
|
||||
selectedIndex = index;
|
||||
startTimer(modelData.action);
|
||||
@@ -589,6 +637,7 @@ SmartPanel {
|
||||
isShutdown: modelData.isShutdown || false
|
||||
isSelected: index === selectedIndex
|
||||
number: index + 1
|
||||
buttonIndex: index
|
||||
onClicked: {
|
||||
selectedIndex = index;
|
||||
startTimer(modelData.action);
|
||||
@@ -653,16 +702,16 @@ SmartPanel {
|
||||
width: Style.marginXL
|
||||
height: width
|
||||
radius: Math.min(Style.radiusM, height / 2)
|
||||
color: (buttonRoot.isSelected || mouseArea.containsMouse) ? Color.mPrimary : Qt.alpha(Color.mSurfaceVariant, 0.5)
|
||||
color: (buttonRoot.isSelected || buttonRoot.effectiveHover) ? Color.mPrimary : Qt.alpha(Color.mSurfaceVariant, 0.5)
|
||||
border.width: Style.borderS
|
||||
border.color: (buttonRoot.isSelected || mouseArea.containsMouse) ? Color.mPrimary : Color.mOutline
|
||||
border.color: (buttonRoot.isSelected || buttonRoot.effectiveHover) ? Color.mPrimary : Color.mOutline
|
||||
visible: Settings.data.sessionMenu.showNumberLabels && buttonRoot.number > 0
|
||||
|
||||
NText {
|
||||
anchors.centerIn: parent
|
||||
text: buttonRoot.number
|
||||
pointSize: Style.fontSizeS
|
||||
color: (buttonRoot.isSelected || mouseArea.containsMouse) ? Color.mOnPrimary : Color.mOnSurface
|
||||
color: (buttonRoot.isSelected || buttonRoot.effectiveHover) ? Color.mOnPrimary : Color.mOnSurface
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
@@ -680,6 +729,10 @@ SmartPanel {
|
||||
property bool isShutdown: false
|
||||
property bool isSelected: false
|
||||
property int number: 0
|
||||
property int buttonIndex: -1
|
||||
|
||||
// Effective hover state that respects ignoreMouseHover
|
||||
readonly property bool effectiveHover: !root.ignoreMouseHover && mouseArea.containsMouse
|
||||
|
||||
signal clicked
|
||||
|
||||
@@ -689,7 +742,7 @@ SmartPanel {
|
||||
if (pending) {
|
||||
return Qt.alpha(Color.mPrimary, 0.08);
|
||||
}
|
||||
if (isSelected || mouseArea.containsMouse) {
|
||||
if (isSelected || effectiveHover) {
|
||||
return Color.mHover;
|
||||
}
|
||||
return "transparent";
|
||||
@@ -718,9 +771,9 @@ SmartPanel {
|
||||
color: {
|
||||
if (buttonRoot.pending)
|
||||
return Color.mPrimary;
|
||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !buttonRoot.effectiveHover)
|
||||
return Color.mError;
|
||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||
if (buttonRoot.isSelected || buttonRoot.effectiveHover)
|
||||
return Color.mOnHover;
|
||||
return Color.mOnSurface;
|
||||
}
|
||||
@@ -753,9 +806,9 @@ SmartPanel {
|
||||
color: {
|
||||
if (buttonRoot.pending)
|
||||
return Color.mPrimary;
|
||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !buttonRoot.effectiveHover)
|
||||
return Color.mError;
|
||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||
if (buttonRoot.isSelected || buttonRoot.effectiveHover)
|
||||
return Color.mOnHover;
|
||||
return Color.mOnSurface;
|
||||
}
|
||||
@@ -788,7 +841,7 @@ SmartPanel {
|
||||
text: buttonRoot.number
|
||||
pointSize: Style.fontSizeS
|
||||
color: {
|
||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||
if (buttonRoot.isSelected || buttonRoot.effectiveHover)
|
||||
return Color.mOnHover;
|
||||
return Color.mOnSurface;
|
||||
}
|
||||
@@ -809,6 +862,12 @@ SmartPanel {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onEntered: {
|
||||
if (!root.ignoreMouseHover) {
|
||||
selectedIndex = buttonRoot.buttonIndex;
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: buttonRoot.clicked()
|
||||
}
|
||||
}
|
||||
@@ -823,17 +882,21 @@ SmartPanel {
|
||||
property bool isShutdown: false
|
||||
property bool isSelected: false
|
||||
property int number: 0
|
||||
property int buttonIndex: -1
|
||||
|
||||
// Effective hover state that respects ignoreMouseHover
|
||||
readonly property bool effectiveHover: !root.ignoreMouseHover && mouseArea.containsMouse
|
||||
|
||||
signal clicked
|
||||
|
||||
property real hoverScale: (isSelected || mouseArea.containsMouse) ? 1.05 : 1.0
|
||||
property real hoverScale: (isSelected || effectiveHover) ? 1.05 : 1.0
|
||||
|
||||
radius: Style.radiusL
|
||||
color: {
|
||||
if (pending) {
|
||||
return Qt.alpha(Color.mPrimary, 1.0);
|
||||
}
|
||||
if (isSelected || mouseArea.containsMouse) {
|
||||
if (isSelected || effectiveHover) {
|
||||
return Qt.alpha(Color.mPrimary, 1.0);
|
||||
}
|
||||
return Qt.alpha(Color.mSurfaceVariant, Settings.data.ui.panelBackgroundOpacity);
|
||||
@@ -885,9 +948,9 @@ SmartPanel {
|
||||
color: {
|
||||
if (largeButtonRoot.pending)
|
||||
return Color.mOnPrimary;
|
||||
if (largeButtonRoot.isShutdown && !largeButtonRoot.isSelected && !mouseArea.containsMouse)
|
||||
if (largeButtonRoot.isShutdown && !largeButtonRoot.isSelected && !largeButtonRoot.effectiveHover)
|
||||
return Color.mError;
|
||||
if (largeButtonRoot.isSelected || mouseArea.containsMouse)
|
||||
if (largeButtonRoot.isSelected || largeButtonRoot.effectiveHover)
|
||||
return Color.mOnPrimary;
|
||||
return Color.mOnSurface;
|
||||
}
|
||||
@@ -897,7 +960,7 @@ SmartPanel {
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
property real iconScale: (largeButtonRoot.isSelected || mouseArea.containsMouse) ? 1.1 : 1.0
|
||||
property real iconScale: (largeButtonRoot.isSelected || largeButtonRoot.effectiveHover) ? 1.1 : 1.0
|
||||
|
||||
transform: Scale {
|
||||
origin.x: iconElement.width / 2
|
||||
@@ -931,9 +994,9 @@ SmartPanel {
|
||||
color: {
|
||||
if (largeButtonRoot.pending)
|
||||
return Color.mOnPrimary;
|
||||
if (largeButtonRoot.isShutdown && !largeButtonRoot.isSelected && !mouseArea.containsMouse)
|
||||
if (largeButtonRoot.isShutdown && !largeButtonRoot.isSelected && !largeButtonRoot.effectiveHover)
|
||||
return Color.mError;
|
||||
if (largeButtonRoot.isSelected || mouseArea.containsMouse)
|
||||
if (largeButtonRoot.isSelected || largeButtonRoot.effectiveHover)
|
||||
return Color.mOnPrimary;
|
||||
return Color.mOnSurface;
|
||||
}
|
||||
@@ -967,7 +1030,7 @@ SmartPanel {
|
||||
text: largeButtonRoot.number
|
||||
pointSize: Style.fontSizeM
|
||||
color: {
|
||||
if (largeButtonRoot.isSelected || mouseArea.containsMouse)
|
||||
if (largeButtonRoot.isSelected || largeButtonRoot.effectiveHover)
|
||||
return Color.mOnPrimary;
|
||||
return Color.mOnSurface;
|
||||
}
|
||||
@@ -987,6 +1050,12 @@ SmartPanel {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onEntered: {
|
||||
if (!root.ignoreMouseHover) {
|
||||
selectedIndex = largeButtonRoot.buttonIndex;
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: largeButtonRoot.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user