systray
This commit is contained in:
@@ -5,6 +5,7 @@ import Quickshell.Hyprland
|
||||
|
||||
import "Windows/QuickSettings"
|
||||
import "Windows/AppLauncher"
|
||||
import "Windows/PowerMenu"
|
||||
|
||||
PanelWindow {
|
||||
id: overlay
|
||||
@@ -76,4 +77,9 @@ PanelWindow {
|
||||
id: appLauncherWindow
|
||||
manager: ShellStateManager
|
||||
}
|
||||
|
||||
PowerMenu {
|
||||
id: powerMenuWindow
|
||||
manager: ShellStateManager
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ QtObject {
|
||||
context = "appLauncher";
|
||||
else if (ShellStateManager.quickSettingsOpen)
|
||||
context = "quickSettings";
|
||||
else if (ShellStateManager.powerMenuOpen)
|
||||
context = "powerMenu";
|
||||
var handler = handlers[context];
|
||||
if (handler) {
|
||||
var handled = handler(key);
|
||||
@@ -47,6 +49,8 @@ QtObject {
|
||||
ShellStateManager.closeAppLauncher();
|
||||
} else if (context === "quickSettings") {
|
||||
ShellStateManager.closeQuickSettings();
|
||||
} else if (context === "powerMenu") {
|
||||
ShellStateManager.closePowerMenu();
|
||||
} else if (context === "topbar") {
|
||||
ShellStateManager.closeShell();
|
||||
Hyprland.dispatch("submap reset");
|
||||
|
||||
@@ -10,6 +10,7 @@ QtObject {
|
||||
property bool shellOpen: false
|
||||
property bool quickSettingsOpen: false
|
||||
property bool appLauncherOpen: false
|
||||
property bool powerMenuOpen: false
|
||||
property var appUsageCounts: ({})
|
||||
property string appUsagePath: {
|
||||
var homeDir = Quickshell.env("HOME");
|
||||
@@ -26,6 +27,8 @@ QtObject {
|
||||
signal quickSettingsClosed
|
||||
signal appLauncherOpened
|
||||
signal appLauncherClosed
|
||||
signal powerMenuOpened
|
||||
signal powerMenuClosed
|
||||
signal windowRequested(string name, var payload)
|
||||
|
||||
function openShell() {
|
||||
@@ -47,6 +50,9 @@ QtObject {
|
||||
if (appLauncherOpen) {
|
||||
closeAppLauncher();
|
||||
}
|
||||
if (powerMenuOpen) {
|
||||
closePowerMenu();
|
||||
}
|
||||
shellOpen = false;
|
||||
shellClosed();
|
||||
}
|
||||
@@ -72,6 +78,9 @@ QtObject {
|
||||
if (appLauncherOpen) {
|
||||
closeAppLauncher();
|
||||
}
|
||||
if (powerMenuOpen) {
|
||||
closePowerMenu();
|
||||
}
|
||||
if (!quickSettingsOpen) {
|
||||
quickSettingsOpen = true;
|
||||
quickSettingsOpened();
|
||||
@@ -97,6 +106,9 @@ QtObject {
|
||||
if (quickSettingsOpen) {
|
||||
closeQuickSettings();
|
||||
}
|
||||
if (powerMenuOpen) {
|
||||
closePowerMenu();
|
||||
}
|
||||
if (!appLauncherOpen) {
|
||||
appLauncherOpen = true;
|
||||
appLauncherOpened();
|
||||
@@ -116,6 +128,34 @@ QtObject {
|
||||
appLauncherOpen ? closeAppLauncher() : openAppLauncher(payload);
|
||||
}
|
||||
|
||||
function openPowerMenu(payload) {
|
||||
var normalizedPayload = payload || ({});
|
||||
console.log("ShellStateManager: openPowerMenu", normalizedPayload);
|
||||
if (quickSettingsOpen) {
|
||||
closeQuickSettings();
|
||||
}
|
||||
if (appLauncherOpen) {
|
||||
closeAppLauncher();
|
||||
}
|
||||
if (!powerMenuOpen) {
|
||||
powerMenuOpen = true;
|
||||
powerMenuOpened();
|
||||
}
|
||||
requestWindow("powerMenu", normalizedPayload);
|
||||
}
|
||||
|
||||
function closePowerMenu() {
|
||||
if (powerMenuOpen) {
|
||||
console.log("ShellStateManager: closePowerMenu");
|
||||
powerMenuOpen = false;
|
||||
powerMenuClosed();
|
||||
}
|
||||
}
|
||||
|
||||
function togglePowerMenu(payload) {
|
||||
powerMenuOpen ? closePowerMenu() : openPowerMenu(payload);
|
||||
}
|
||||
|
||||
function bumpAppUsage(id) {
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
@@ -55,6 +55,12 @@ Item {
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (iconSources[selectedIndex] === "power.png") {
|
||||
ShellStateManager.openPowerMenu({
|
||||
source: "Topbar"
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -90,7 +96,7 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
selected: topbar.selectedIndex == repeatitem.index
|
||||
iconSource: topbar.iconSources[repeatitem.index]
|
||||
showSoul: !topbar.manager.quickSettingsOpen && !topbar.manager.appLauncherOpen
|
||||
showSoul: !topbar.manager.quickSettingsOpen && !topbar.manager.appLauncherOpen && !topbar.manager.powerMenuOpen
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -107,6 +113,11 @@ Item {
|
||||
source: "Topbar"
|
||||
});
|
||||
}
|
||||
if (topbar.iconSources[repeatitem.index] === "power.png") {
|
||||
ShellStateManager.openPowerMenu({
|
||||
source: "Topbar"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
44
Shell/Windows/PowerMenu/PowerMenu.qml
Normal file
44
Shell/Windows/PowerMenu/PowerMenu.qml
Normal file
@@ -0,0 +1,44 @@
|
||||
import QtQuick
|
||||
import "../.."
|
||||
import "../../Window" as ShellWindow
|
||||
|
||||
ShellWindow.Window {
|
||||
id: powerMenuWindow
|
||||
property var manager: ShellStateManager
|
||||
|
||||
property var powerMenuApp: null
|
||||
|
||||
width: 1217 + 52
|
||||
height: 767 + 52
|
||||
visible: manager ? manager.powerMenuOpen : false
|
||||
anchors.centerIn: parent
|
||||
|
||||
Loader {
|
||||
id: powerMenuLoader
|
||||
anchors.fill: parent
|
||||
asynchronous: true
|
||||
source: "./PowerMenuApp.qml"
|
||||
onLoaded: {
|
||||
powerMenuApp = item;
|
||||
if (powerMenuApp)
|
||||
powerMenuApp.manager = manager;
|
||||
}
|
||||
}
|
||||
|
||||
onManagerChanged: {
|
||||
if (powerMenuApp)
|
||||
powerMenuApp.manager = manager;
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: powerMenuKeyHandler
|
||||
function handle(key) {
|
||||
if (powerMenuApp && powerMenuApp.handleKey)
|
||||
return powerMenuApp.handleKey(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
Component.onCompleted: ShellInputManager.registerHandler("powerMenu", handle)
|
||||
Component.onDestruction: ShellInputManager.unregisterHandler("powerMenu")
|
||||
}
|
||||
}
|
||||
522
Shell/Windows/PowerMenu/PowerMenuApp.qml
Normal file
522
Shell/Windows/PowerMenu/PowerMenuApp.qml
Normal file
@@ -0,0 +1,522 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Services.SystemTray
|
||||
import Quickshell.Widgets
|
||||
import "../.."
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: parent ? parent.width : 1280
|
||||
height: parent ? parent.height : 820
|
||||
focus: true
|
||||
|
||||
property ShellStateManager manager: null
|
||||
|
||||
// ITEM/APPS-like layout constants
|
||||
property int menuTop: 140
|
||||
property int lineHeight: 79
|
||||
property int iconSize: 36
|
||||
property int textStartX: 239
|
||||
property int textRightPadding: 96
|
||||
property int visibleRows: Math.max(1, Math.floor((height - menuTop - 64) / lineHeight))
|
||||
|
||||
property bool inSubmenu: false
|
||||
property int traySelection: 0
|
||||
property int submenuSelection: 0
|
||||
property int scrollOffset: 0
|
||||
property var menuStack: []
|
||||
property var currentMenuHandle: null
|
||||
property var submenuSourceTrayItem: null
|
||||
property int submenuPollTicks: 0
|
||||
|
||||
readonly property int activeSelection: inSubmenu ? submenuSelection : traySelection
|
||||
|
||||
ListModel {
|
||||
id: submenuData
|
||||
}
|
||||
|
||||
QsMenuOpener {
|
||||
id: opener
|
||||
menu: root.currentMenuHandle
|
||||
}
|
||||
|
||||
// Raw source entries from current DBus menu (hidden)
|
||||
Repeater {
|
||||
id: submenuSourceRepeater
|
||||
model: opener.children
|
||||
|
||||
delegate: Item {
|
||||
visible: false
|
||||
width: 0
|
||||
height: 0
|
||||
property var entry: modelData
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: submenuPollTimer
|
||||
interval: 120
|
||||
repeat: true
|
||||
running: false
|
||||
onTriggered: {
|
||||
if (!root.currentMenuHandle && root.submenuSourceTrayItem && root.submenuSourceTrayItem.menu)
|
||||
root.currentMenuHandle = root.submenuSourceTrayItem.menu;
|
||||
|
||||
root.rebuildSubmenuData();
|
||||
root.submenuPollTicks = root.submenuPollTicks + 1;
|
||||
if (submenuData.count > 0 || root.submenuPollTicks >= 20)
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
if (manager && manager.closeShell)
|
||||
manager.closeShell();
|
||||
}
|
||||
|
||||
function clamp(v, lo, hi) {
|
||||
return Math.max(lo, Math.min(hi, v));
|
||||
}
|
||||
|
||||
function trayCount() {
|
||||
return trayRepeater ? trayRepeater.count : 0;
|
||||
}
|
||||
|
||||
function submenuCount() {
|
||||
return submenuData.count;
|
||||
}
|
||||
|
||||
function currentCount() {
|
||||
return inSubmenu ? submenuCount() : trayCount();
|
||||
}
|
||||
|
||||
function wrapIndex(i) {
|
||||
const length = currentCount();
|
||||
if (length === 0)
|
||||
return 0;
|
||||
return (i + length) % length;
|
||||
}
|
||||
|
||||
function selectedTrayDelegate() {
|
||||
if (trayCount() <= 0)
|
||||
return null;
|
||||
return trayRepeater.itemAt(traySelection);
|
||||
}
|
||||
|
||||
function selectedTrayItem() {
|
||||
const delegate = selectedTrayDelegate();
|
||||
return delegate ? delegate.trayItem : null;
|
||||
}
|
||||
|
||||
function selectedMenuEntry() {
|
||||
if (submenuSelection < 0 || submenuSelection >= submenuData.count)
|
||||
return null;
|
||||
const row = submenuData.get(submenuSelection);
|
||||
return row ? row.entry : null;
|
||||
}
|
||||
|
||||
function normalizeSelection() {
|
||||
const length = currentCount();
|
||||
if (length <= 0) {
|
||||
if (inSubmenu)
|
||||
submenuSelection = 0;
|
||||
else
|
||||
traySelection = 0;
|
||||
scrollOffset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (inSubmenu)
|
||||
submenuSelection = clamp(submenuSelection, 0, length - 1);
|
||||
else
|
||||
traySelection = clamp(traySelection, 0, length - 1);
|
||||
|
||||
const currentSelection = activeSelection;
|
||||
const maxOffset = Math.max(0, length - visibleRows);
|
||||
|
||||
if (currentSelection < scrollOffset)
|
||||
scrollOffset = currentSelection;
|
||||
else if (currentSelection >= scrollOffset + visibleRows)
|
||||
scrollOffset = Math.max(0, currentSelection - visibleRows + 1);
|
||||
|
||||
scrollOffset = clamp(scrollOffset, 0, maxOffset);
|
||||
}
|
||||
|
||||
function rebuildSubmenuData() {
|
||||
submenuData.clear();
|
||||
|
||||
const count = submenuSourceRepeater ? submenuSourceRepeater.count : 0;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const sourceItem = submenuSourceRepeater.itemAt(i);
|
||||
const entry = sourceItem ? sourceItem.entry : null;
|
||||
if (!entry || entry.isSeparator)
|
||||
continue;
|
||||
|
||||
submenuData.append({
|
||||
entry: entry
|
||||
});
|
||||
}
|
||||
|
||||
submenuSelection = clamp(submenuSelection, 0, Math.max(0, submenuData.count - 1));
|
||||
normalizeSelection();
|
||||
}
|
||||
|
||||
function enterSubmenu(menuHandle) {
|
||||
currentMenuHandle = menuHandle;
|
||||
inSubmenu = true;
|
||||
submenuSelection = 0;
|
||||
scrollOffset = 0;
|
||||
submenuData.clear();
|
||||
submenuPollTicks = 0;
|
||||
Qt.callLater(function () {
|
||||
rebuildSubmenuData();
|
||||
submenuPollTimer.restart();
|
||||
});
|
||||
}
|
||||
|
||||
function openSelectedTraySubmenu() {
|
||||
const trayItem = selectedTrayItem();
|
||||
if (!trayItem)
|
||||
return;
|
||||
|
||||
if (!trayItem.hasMenu) {
|
||||
trayItem.activate();
|
||||
closeAll();
|
||||
return;
|
||||
}
|
||||
|
||||
menuStack = [];
|
||||
submenuSourceTrayItem = trayItem;
|
||||
enterSubmenu(trayItem.menu);
|
||||
}
|
||||
|
||||
function triggerSelectedSubmenuEntry() {
|
||||
const entry = selectedMenuEntry();
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
if (entry.hasChildren) {
|
||||
const stackCopy = menuStack.slice(0);
|
||||
stackCopy.push(currentMenuHandle);
|
||||
menuStack = stackCopy;
|
||||
submenuSourceTrayItem = null;
|
||||
enterSubmenu(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
entry.triggered();
|
||||
closeAll();
|
||||
}
|
||||
|
||||
function backAction() {
|
||||
if (inSubmenu) {
|
||||
if (menuStack.length > 0) {
|
||||
const stackCopy = menuStack.slice(0);
|
||||
const parentHandle = stackCopy.pop();
|
||||
menuStack = stackCopy;
|
||||
submenuSourceTrayItem = null;
|
||||
enterSubmenu(parentHandle);
|
||||
} else {
|
||||
inSubmenu = false;
|
||||
currentMenuHandle = null;
|
||||
submenuSourceTrayItem = null;
|
||||
submenuData.clear();
|
||||
submenuPollTimer.stop();
|
||||
scrollOffset = 0;
|
||||
normalizeSelection();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (manager && manager.closePowerMenu)
|
||||
manager.closePowerMenu();
|
||||
}
|
||||
|
||||
function handleKey(key) {
|
||||
switch (key) {
|
||||
case Qt.Key_Up:
|
||||
if (inSubmenu)
|
||||
submenuSelection = wrapIndex(submenuSelection - 1);
|
||||
else
|
||||
traySelection = wrapIndex(traySelection - 1);
|
||||
normalizeSelection();
|
||||
return true;
|
||||
case Qt.Key_Down:
|
||||
if (inSubmenu)
|
||||
submenuSelection = wrapIndex(submenuSelection + 1);
|
||||
else
|
||||
traySelection = wrapIndex(traySelection + 1);
|
||||
normalizeSelection();
|
||||
return true;
|
||||
case Qt.Key_Z:
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
if (inSubmenu)
|
||||
triggerSelectedSubmenuEntry();
|
||||
else
|
||||
openSelectedTraySubmenu();
|
||||
return true;
|
||||
case Qt.Key_X:
|
||||
case Qt.Key_Shift:
|
||||
case Qt.Key_Escape:
|
||||
backAction();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: manager
|
||||
ignoreUnknownSignals: true
|
||||
function onPowerMenuOpened() {
|
||||
root.inSubmenu = false;
|
||||
root.currentMenuHandle = null;
|
||||
root.submenuSourceTrayItem = null;
|
||||
root.menuStack = [];
|
||||
root.submenuPollTicks = 0;
|
||||
submenuPollTimer.stop();
|
||||
submenuData.clear();
|
||||
root.scrollOffset = 0;
|
||||
root.traySelection = 0;
|
||||
root.submenuSelection = 0;
|
||||
root.normalizeSelection();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SystemTray.items
|
||||
ignoreUnknownSignals: true
|
||||
function onCountChanged() {
|
||||
root.normalizeSelection();
|
||||
}
|
||||
function onModelReset() {
|
||||
root.normalizeSelection();
|
||||
}
|
||||
function onRowsInserted() {
|
||||
root.normalizeSelection();
|
||||
}
|
||||
function onRowsRemoved() {
|
||||
root.normalizeSelection();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: opener.children
|
||||
ignoreUnknownSignals: true
|
||||
function onCountChanged() {
|
||||
root.rebuildSubmenuData();
|
||||
}
|
||||
function onModelReset() {
|
||||
root.rebuildSubmenuData();
|
||||
}
|
||||
function onRowsInserted() {
|
||||
root.rebuildSubmenuData();
|
||||
}
|
||||
function onRowsRemoved() {
|
||||
root.rebuildSubmenuData();
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: inSubmenu ? "OPTIONS" : "POWER"
|
||||
font.family: "8bitoperator JVE"
|
||||
font.pixelSize: 71
|
||||
renderType: Text.NativeRendering
|
||||
font.hintingPreference: Font.PreferNoHinting
|
||||
smooth: false
|
||||
antialiasing: false
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "#ffffff"
|
||||
y: 32
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: trayRepeater
|
||||
model: SystemTray.items
|
||||
|
||||
delegate: Item {
|
||||
width: root.width
|
||||
height: root.lineHeight
|
||||
x: 0
|
||||
y: root.menuTop + (index - root.scrollOffset) * root.lineHeight
|
||||
visible: !root.inSubmenu && index >= root.scrollOffset && index < root.scrollOffset + root.visibleRows
|
||||
|
||||
property var trayItem: modelData
|
||||
|
||||
Text {
|
||||
x: root.textStartX
|
||||
y: 0
|
||||
text: trayItem && trayItem.tooltipTitle ? trayItem.tooltipTitle : (trayItem ? trayItem.title : "")
|
||||
width: root.width - root.textStartX - root.textRightPadding
|
||||
font.family: "8bitoperator JVE"
|
||||
font.pixelSize: 71
|
||||
font.letterSpacing: 1
|
||||
renderType: Text.NativeRendering
|
||||
font.hintingPreference: Font.PreferNoHinting
|
||||
smooth: false
|
||||
antialiasing: false
|
||||
wrapMode: Text.NoWrap
|
||||
elide: Text.ElideRight
|
||||
color: root.activeSelection == index ? "#fefe00" : "#ffffff"
|
||||
}
|
||||
|
||||
IconImage {
|
||||
id: trayIcon
|
||||
x: 182
|
||||
y: 8 + 14
|
||||
implicitSize: root.iconSize
|
||||
source: trayItem ? trayItem.icon : ""
|
||||
asynchronous: true
|
||||
}
|
||||
|
||||
Image {
|
||||
source: "../QuickSettings/soul.png"
|
||||
width: 36
|
||||
height: 36
|
||||
x: trayIcon.x
|
||||
y: trayIcon.y
|
||||
opacity: 0.7
|
||||
visible: root.activeSelection == index
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
root.traySelection = index;
|
||||
root.normalizeSelection();
|
||||
}
|
||||
onClicked: {
|
||||
root.traySelection = index;
|
||||
root.normalizeSelection();
|
||||
root.openSelectedTraySubmenu();
|
||||
}
|
||||
onWheel: function (wheel) {
|
||||
if (!trayItem)
|
||||
return;
|
||||
const horizontal = Math.abs(wheel.angleDelta.x) > Math.abs(wheel.angleDelta.y);
|
||||
const delta = horizontal ? wheel.angleDelta.x : wheel.angleDelta.y;
|
||||
trayItem.scroll(delta, horizontal);
|
||||
wheel.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: submenuRepeater
|
||||
model: submenuData
|
||||
|
||||
delegate: Item {
|
||||
property var entry: model.entry
|
||||
width: root.width
|
||||
height: root.lineHeight
|
||||
x: 0
|
||||
y: root.menuTop + (index - root.scrollOffset) * root.lineHeight
|
||||
visible: root.inSubmenu && index >= root.scrollOffset && index < root.scrollOffset + root.visibleRows
|
||||
|
||||
Text {
|
||||
x: root.textStartX
|
||||
y: 0
|
||||
width: root.width - root.textStartX - root.textRightPadding
|
||||
text: {
|
||||
if (!entry)
|
||||
return "";
|
||||
|
||||
let prefix = "";
|
||||
if (entry.buttonType === QsMenuButtonType.CheckBox)
|
||||
prefix = entry.checkState === Qt.Checked ? "[x] " : "[ ] ";
|
||||
else if (entry.buttonType === QsMenuButtonType.RadioButton)
|
||||
prefix = entry.checkState === Qt.Checked ? "(x) " : "( ) ";
|
||||
|
||||
return prefix + String(entry.text || "") + (entry.hasChildren ? " >" : "");
|
||||
}
|
||||
font.family: "8bitoperator JVE"
|
||||
font.pixelSize: 71
|
||||
font.letterSpacing: 1
|
||||
renderType: Text.NativeRendering
|
||||
font.hintingPreference: Font.PreferNoHinting
|
||||
smooth: false
|
||||
antialiasing: false
|
||||
wrapMode: Text.NoWrap
|
||||
elide: Text.ElideRight
|
||||
color: root.activeSelection == index ? "#fefe00" : "#ffffff"
|
||||
}
|
||||
|
||||
Image {
|
||||
source: "../QuickSettings/soul.png"
|
||||
width: 36
|
||||
height: 36
|
||||
x: 182
|
||||
y: 8 + 14
|
||||
opacity: 0.7
|
||||
visible: root.activeSelection == index
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
root.submenuSelection = index;
|
||||
root.normalizeSelection();
|
||||
}
|
||||
onClicked: {
|
||||
root.submenuSelection = index;
|
||||
root.normalizeSelection();
|
||||
root.triggerSelectedSubmenuEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WheelHandler {
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: function (event) {
|
||||
const count = root.currentCount();
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
const delta = event.angleDelta.y > 0 ? -1 : 1;
|
||||
if (root.inSubmenu)
|
||||
root.submenuSelection = root.wrapIndex(root.submenuSelection + delta);
|
||||
else
|
||||
root.traySelection = root.wrapIndex(root.traySelection + delta);
|
||||
|
||||
root.normalizeSelection();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: !root.inSubmenu && trayCount() === 0
|
||||
text: "NO TRAY ITEMS"
|
||||
font.family: "8bitoperator JVE"
|
||||
font.pixelSize: 54
|
||||
font.letterSpacing: 1
|
||||
renderType: Text.NativeRendering
|
||||
font.hintingPreference: Font.PreferNoHinting
|
||||
smooth: false
|
||||
antialiasing: false
|
||||
color: "#ffffff"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: 302
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: root.inSubmenu && !submenuPollTimer.running && submenuCount() === 0
|
||||
text: "NO OPTIONS"
|
||||
font.family: "8bitoperator JVE"
|
||||
font.pixelSize: 54
|
||||
font.letterSpacing: 1
|
||||
renderType: Text.NativeRendering
|
||||
font.hintingPreference: Font.PreferNoHinting
|
||||
smooth: false
|
||||
antialiasing: false
|
||||
color: "#ffffff"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: 302
|
||||
}
|
||||
|
||||
Component.onCompleted: normalizeSelection()
|
||||
}
|
||||
Reference in New Issue
Block a user