add noctalia and fuzzel
This commit is contained in:
+252
@@ -0,0 +1,252 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
property var entriesModel: []
|
||||
property var updateEntry
|
||||
property var reorderEntries
|
||||
property var openEntrySettingsDialog
|
||||
|
||||
// List of items
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: listView.contentHeight
|
||||
|
||||
NListView {
|
||||
id: listView
|
||||
anchors.fill: parent
|
||||
spacing: Style.marginS
|
||||
interactive: false
|
||||
reserveScrollbarSpace: false
|
||||
model: root.entriesModel
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
width: listView.availableWidth
|
||||
height: contentRow.height
|
||||
|
||||
required property int index
|
||||
required property var modelData
|
||||
|
||||
property bool dragging: false
|
||||
property int dragStartY: 0
|
||||
property int dragStartIndex: -1
|
||||
property int dragTargetIndex: -1
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Style.radiusM
|
||||
color: delegateItem.dragging ? Color.mSurfaceVariant : "transparent"
|
||||
border.color: delegateItem.dragging ? Color.mOutline : "transparent"
|
||||
border.width: Style.borderS
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: contentRow
|
||||
width: parent.width
|
||||
spacing: Style.marginS
|
||||
|
||||
// Drag handle
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Style.baseWidgetSize * 0.7
|
||||
Layout.preferredHeight: Style.baseWidgetSize * 0.7
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
radius: Style.radiusXS
|
||||
color: dragHandleMouseArea.containsMouse ? Color.mSurfaceVariant : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: 3
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Style.baseWidgetSize * 0.28
|
||||
Layout.preferredHeight: 2
|
||||
radius: 1
|
||||
color: Color.mOutline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dragHandleMouseArea
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.SizeVerCursor
|
||||
hoverEnabled: true
|
||||
preventStealing: false
|
||||
z: 1000
|
||||
|
||||
onPressed: mouse => {
|
||||
delegateItem.dragStartIndex = delegateItem.index;
|
||||
delegateItem.dragTargetIndex = delegateItem.index;
|
||||
delegateItem.dragStartY = delegateItem.y;
|
||||
delegateItem.dragging = true;
|
||||
delegateItem.z = 999;
|
||||
preventStealing = true;
|
||||
}
|
||||
|
||||
onPositionChanged: mouse => {
|
||||
if (delegateItem.dragging) {
|
||||
var dy = mouse.y - height / 2;
|
||||
var newY = delegateItem.y + dy;
|
||||
newY = Math.max(0, Math.min(newY, listView.contentHeight - delegateItem.height));
|
||||
delegateItem.y = newY;
|
||||
var targetIndex = Math.floor((newY + delegateItem.height / 2) / (delegateItem.height + Style.marginS));
|
||||
targetIndex = Math.max(0, Math.min(targetIndex, listView.count - 1));
|
||||
delegateItem.dragTargetIndex = targetIndex;
|
||||
}
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
preventStealing = false;
|
||||
if (delegateItem.dragStartIndex !== -1 && delegateItem.dragTargetIndex !== -1 && delegateItem.dragStartIndex !== delegateItem.dragTargetIndex) {
|
||||
root.reorderEntries(delegateItem.dragStartIndex, delegateItem.dragTargetIndex);
|
||||
}
|
||||
delegateItem.dragging = false;
|
||||
delegateItem.dragStartIndex = -1;
|
||||
delegateItem.dragTargetIndex = -1;
|
||||
delegateItem.z = 0;
|
||||
}
|
||||
|
||||
onCanceled: {
|
||||
preventStealing = false;
|
||||
delegateItem.dragging = false;
|
||||
delegateItem.dragStartIndex = -1;
|
||||
delegateItem.dragTargetIndex = -1;
|
||||
delegateItem.z = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enable checkbox
|
||||
Rectangle {
|
||||
Layout.preferredWidth: Style.baseWidgetSize * 0.7
|
||||
Layout.preferredHeight: Style.baseWidgetSize * 0.7
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
radius: Style.radiusXS
|
||||
color: modelData.enabled ? Color.mPrimary : Color.mSurface
|
||||
border.color: Color.mOutline
|
||||
border.width: Style.borderS
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
|
||||
NIcon {
|
||||
visible: modelData.enabled
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: -1
|
||||
icon: "check"
|
||||
color: Color.mOnPrimary
|
||||
pointSize: Math.max(Style.fontSizeXS, Style.baseWidgetSize * 0.35)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.updateEntry(index, {
|
||||
"enabled": !modelData.enabled
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Label
|
||||
NText {
|
||||
Layout.fillWidth: true
|
||||
text: modelData.text
|
||||
color: Color.mOnSurface
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
// Countdown toggle (only shown when global countdown is enabled)
|
||||
NIconButtonHot {
|
||||
visible: Settings.data.sessionMenu.enableCountdown
|
||||
icon: "clock"
|
||||
hot: modelData.countdownEnabled !== undefined ? modelData.countdownEnabled : true
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
tooltipText: I18n.tr("common.countdown")
|
||||
onClicked: root.updateEntry(delegateItem.index, {
|
||||
"countdownEnabled": !(modelData.countdownEnabled !== undefined ? modelData.countdownEnabled : true)
|
||||
})
|
||||
}
|
||||
|
||||
// Settings button (cogwheel)
|
||||
NIconButton {
|
||||
icon: "settings"
|
||||
tooltipText: I18n.tr("panels.session-menu.entry-settings-tooltip")
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
onClicked: root.openEntrySettingsDialog(delegateItem.index)
|
||||
}
|
||||
}
|
||||
|
||||
// Position binding for non-dragging state
|
||||
y: {
|
||||
if (delegateItem.dragging) {
|
||||
return delegateItem.y;
|
||||
}
|
||||
|
||||
var draggedIndex = -1;
|
||||
var targetIndex = -1;
|
||||
for (var i = 0; i < listView.count; i++) {
|
||||
var item = listView.itemAtIndex(i);
|
||||
if (item && item.dragging) {
|
||||
draggedIndex = item.dragStartIndex;
|
||||
targetIndex = item.dragTargetIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (draggedIndex !== -1 && targetIndex !== -1 && draggedIndex !== targetIndex) {
|
||||
var currentIndex = delegateItem.index;
|
||||
if (draggedIndex < targetIndex) {
|
||||
if (currentIndex > draggedIndex && currentIndex <= targetIndex) {
|
||||
return (currentIndex - 1) * (delegateItem.height + Style.marginS);
|
||||
}
|
||||
} else {
|
||||
if (currentIndex >= targetIndex && currentIndex < draggedIndex) {
|
||||
return (currentIndex + 1) * (delegateItem.height + Style.marginS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return delegateItem.index * (delegateItem.height + Style.marginS);
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
enabled: !delegateItem.dragging
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.session-menu.large-buttons-style-label")
|
||||
description: I18n.tr("panels.session-menu.large-buttons-style-description")
|
||||
checked: Settings.data.sessionMenu.largeButtonsStyle
|
||||
onToggled: checked => Settings.data.sessionMenu.largeButtonsStyle = checked
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
visible: Settings.data.sessionMenu.largeButtonsStyle
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.session-menu.large-buttons-layout-label")
|
||||
description: I18n.tr("panels.session-menu.large-buttons-layout-description")
|
||||
model: [
|
||||
{
|
||||
"key": "grid",
|
||||
"name": I18n.tr("options.session-menu-grid-layout.grid")
|
||||
},
|
||||
{
|
||||
"key": "single-row",
|
||||
"name": I18n.tr("options.session-menu-grid-layout.single-row")
|
||||
}
|
||||
]
|
||||
currentKey: Settings.data.sessionMenu.largeButtonsLayout
|
||||
defaultValue: Settings.getDefaultValue("sessionMenu.largeButtonsLayout")
|
||||
onSelected: key => Settings.data.sessionMenu.largeButtonsLayout = key
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
label: I18n.tr("common.position")
|
||||
description: I18n.tr("panels.session-menu.position-description")
|
||||
Layout.fillWidth: true
|
||||
model: [
|
||||
{
|
||||
"key": "center",
|
||||
"name": I18n.tr("positions.center")
|
||||
},
|
||||
{
|
||||
"key": "top_center",
|
||||
"name": I18n.tr("positions.top-center")
|
||||
},
|
||||
{
|
||||
"key": "top_left",
|
||||
"name": I18n.tr("positions.top-left")
|
||||
},
|
||||
{
|
||||
"key": "top_right",
|
||||
"name": I18n.tr("positions.top-right")
|
||||
},
|
||||
{
|
||||
"key": "bottom_center",
|
||||
"name": I18n.tr("positions.bottom-center")
|
||||
},
|
||||
{
|
||||
"key": "bottom_left",
|
||||
"name": I18n.tr("positions.bottom-left")
|
||||
},
|
||||
{
|
||||
"key": "bottom_right",
|
||||
"name": I18n.tr("positions.bottom-right")
|
||||
}
|
||||
]
|
||||
currentKey: Settings.data.sessionMenu.position
|
||||
onSelected: key => Settings.data.sessionMenu.position = key
|
||||
visible: !Settings.data.sessionMenu.largeButtonsStyle
|
||||
defaultValue: Settings.getDefaultValue("sessionMenu.position")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.session-menu.show-header-label")
|
||||
description: I18n.tr("panels.session-menu.show-header-description")
|
||||
checked: Settings.data.sessionMenu.showHeader
|
||||
onToggled: checked => Settings.data.sessionMenu.showHeader = checked
|
||||
visible: !Settings.data.sessionMenu.largeButtonsStyle
|
||||
defaultValue: Settings.getDefaultValue("sessionMenu.showHeader")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.session-menu.show-keybinds-label")
|
||||
description: I18n.tr("panels.session-menu.show-keybinds-description")
|
||||
checked: Settings.data.sessionMenu.showKeybinds
|
||||
onToggled: checked => Settings.data.sessionMenu.showKeybinds = checked
|
||||
defaultValue: Settings.getDefaultValue("sessionMenu.showKeybinds")
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.session-menu.enable-countdown-label")
|
||||
description: I18n.tr("panels.session-menu.enable-countdown-description")
|
||||
checked: Settings.data.sessionMenu.enableCountdown
|
||||
onToggled: checked => Settings.data.sessionMenu.enableCountdown = checked
|
||||
defaultValue: Settings.getDefaultValue("sessionMenu.enableCountdown")
|
||||
}
|
||||
|
||||
NValueSlider {
|
||||
visible: Settings.data.sessionMenu.enableCountdown
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.session-menu.countdown-duration-label")
|
||||
description: I18n.tr("panels.session-menu.countdown-duration-description")
|
||||
from: 1000
|
||||
to: 30000
|
||||
stepSize: 1000
|
||||
showReset: true
|
||||
value: Settings.data.sessionMenu.countdownDuration
|
||||
onMoved: value => Settings.data.sessionMenu.countdownDuration = value
|
||||
text: Math.round(Settings.data.sessionMenu.countdownDuration / 1000) + "s"
|
||||
defaultValue: Settings.getDefaultValue("sessionMenu.countdownDuration")
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
// Session Menu Entry Settings Dialog Component
|
||||
Popup {
|
||||
id: root
|
||||
|
||||
property int entryIndex: -1
|
||||
property var entryData: null
|
||||
property string entryId: ""
|
||||
property string entryText: ""
|
||||
property string keybindInputText: ""
|
||||
|
||||
signal updateEntryProperties(int index, var properties)
|
||||
|
||||
// Default commands mapping
|
||||
readonly property var defaultCommands: {
|
||||
"lock": I18n.tr("panels.session-menu.entry-settings-default-command-lock"),
|
||||
"suspend": "systemctl suspend || loginctl suspend",
|
||||
"hibernate": "systemctl hibernate || loginctl hibernate",
|
||||
"reboot": "systemctl reboot || loginctl reboot",
|
||||
"rebootToUefi": "systemctl reboot --firmware-setup || loginctl reboot --firmware-setup",
|
||||
"logout": I18n.tr("panels.session-menu.entry-settings-default-command-logout"),
|
||||
"shutdown": "systemctl poweroff || loginctl poweroff",
|
||||
"userspaceReboot": "systemctl soft-reboot"
|
||||
}
|
||||
|
||||
readonly property string defaultCommand: defaultCommands[entryId] || ""
|
||||
|
||||
width: Math.max(content.implicitWidth + padding * 2, 500)
|
||||
height: content.implicitHeight + padding * 2
|
||||
padding: Style.marginXL
|
||||
modal: true
|
||||
closePolicy: Popup.NoAutoClose
|
||||
dim: false
|
||||
anchors.centerIn: parent
|
||||
|
||||
onOpened: {
|
||||
// Load command when popup opens
|
||||
if (entryData) {
|
||||
commandInput.text = entryData.command || "";
|
||||
keybindInputText = entryData.keybind || "";
|
||||
}
|
||||
// Request focus to ensure keyboard input works
|
||||
forceActiveFocus();
|
||||
}
|
||||
|
||||
function save() {
|
||||
root.updateEntryProperties(root.entryIndex, {
|
||||
"command": commandInput.text,
|
||||
"keybind": keybindInputText
|
||||
});
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
id: bgRect
|
||||
|
||||
color: Color.mSurface
|
||||
radius: Style.radiusL
|
||||
border.color: Color.mPrimary
|
||||
border.width: Style.borderM
|
||||
}
|
||||
|
||||
contentItem: FocusScope {
|
||||
id: focusScope
|
||||
focus: true
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
spacing: Style.marginM
|
||||
|
||||
// Title
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
NText {
|
||||
text: I18n.tr("panels.session-menu.entry-settings-title", {
|
||||
"entry": root.entryText
|
||||
})
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("common.close")
|
||||
onClicked: {
|
||||
root.save();
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Color.mOutline
|
||||
}
|
||||
|
||||
// Command input
|
||||
NTextInput {
|
||||
id: commandInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("common.command")
|
||||
description: I18n.tr("panels.session-menu.entry-settings-command-description")
|
||||
placeholderText: I18n.tr("panels.session-menu.entry-settings-command-placeholder")
|
||||
onTextChanged: root.save()
|
||||
}
|
||||
|
||||
// Default command info
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXS
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.session-menu.entry-settings-default-info-label")
|
||||
description: I18n.tr("panels.session-menu.entry-settings-default-info-description")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Default command display
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: defaultCommandText.implicitHeight + Style.margin2M
|
||||
radius: Style.radiusM
|
||||
color: Color.mSurfaceVariant
|
||||
border.color: Color.mOutline
|
||||
border.width: Style.borderS
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginM
|
||||
spacing: Style.marginS
|
||||
|
||||
NIcon {
|
||||
icon: "info"
|
||||
color: Color.mOnSurfaceVariant
|
||||
pointSize: Style.fontSizeM
|
||||
}
|
||||
|
||||
NText {
|
||||
id: defaultCommandText
|
||||
Layout.fillWidth: true
|
||||
text: root.defaultCommand
|
||||
color: Color.mOnSurfaceVariant
|
||||
font.family: "monospace"
|
||||
font.pointSize: Style.fontSizeS
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NKeybindRecorder {
|
||||
id: keybindRecorder
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("common.keybind")
|
||||
description: I18n.tr("placeholders.keybind-recording")
|
||||
allowEmpty: true
|
||||
maxKeybinds: 1
|
||||
requireModifierForNormalKeys: false
|
||||
currentKeybinds: keybindInputText ? [keybindInputText] : []
|
||||
settingsPath: "sessionMenu.powerOptions[" + root.entryIndex + "].keybind"
|
||||
onKeybindsChanged: newKeybinds => {
|
||||
keybindInputText = newKeybinds.length > 0 ? newKeybinds[0] : "";
|
||||
root.save();
|
||||
}
|
||||
}
|
||||
|
||||
// Hidden property to store the text since NKeybindRecorder manages its own state
|
||||
// but we need to initialize it and read from it
|
||||
|
||||
// Bottom spacer to maintain padding
|
||||
Item {
|
||||
Layout.preferredHeight: Style.marginS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+266
@@ -0,0 +1,266 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 0
|
||||
|
||||
property var _activeDialog: null
|
||||
property list<var> entriesModel: []
|
||||
property list<var> entriesDefault: [
|
||||
{
|
||||
"id": "lock",
|
||||
"text": I18n.tr("common.lock"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "suspend",
|
||||
"text": I18n.tr("common.suspend"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "hibernate",
|
||||
"text": I18n.tr("common.hibernate"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "reboot",
|
||||
"text": I18n.tr("common.reboot"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "userspaceReboot",
|
||||
"text": I18n.tr("common.userspace-reboot"),
|
||||
"enabled": false,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "rebootToUefi",
|
||||
"text": I18n.tr("common.reboot-to-uefi"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "logout",
|
||||
"text": I18n.tr("common.logout"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"id": "shutdown",
|
||||
"text": I18n.tr("common.shutdown"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
|
||||
function saveEntries() {
|
||||
var toSave = [];
|
||||
var enabledNumber = 1;
|
||||
|
||||
for (var i = 0; i < entriesModel.length; i++) {
|
||||
var keybind = entriesModel[i].keybind || "";
|
||||
|
||||
if (entriesModel[i].enabled) {
|
||||
// For enabled entries with numeric or empty keybinds, assign sequential number
|
||||
if (keybind === "" || /^\d+$/.test(keybind)) {
|
||||
keybind = String(enabledNumber);
|
||||
}
|
||||
enabledNumber++;
|
||||
} else {
|
||||
// For disabled entries with numeric keybinds, clear them
|
||||
if (/^\d+$/.test(keybind)) {
|
||||
keybind = "";
|
||||
}
|
||||
}
|
||||
|
||||
toSave.push({
|
||||
"action": entriesModel[i].id,
|
||||
"enabled": entriesModel[i].enabled,
|
||||
"countdownEnabled": entriesModel[i].countdownEnabled !== undefined ? entriesModel[i].countdownEnabled : true,
|
||||
"command": entriesModel[i].command || "",
|
||||
"keybind": keybind
|
||||
});
|
||||
}
|
||||
|
||||
// Update local model with renumbered keybinds
|
||||
var newModel = [];
|
||||
for (var i = 0; i < entriesModel.length; i++) {
|
||||
newModel.push(Object.assign({}, entriesModel[i], {
|
||||
"keybind": toSave[i].keybind
|
||||
}));
|
||||
}
|
||||
entriesModel = newModel;
|
||||
|
||||
Settings.data.sessionMenu.powerOptions = toSave;
|
||||
}
|
||||
|
||||
function updateEntry(idx, properties) {
|
||||
var newModel = entriesModel.slice();
|
||||
newModel[idx] = Object.assign({}, newModel[idx], properties);
|
||||
entriesModel = newModel;
|
||||
saveEntries();
|
||||
}
|
||||
|
||||
function reorderEntries(fromIndex, toIndex) {
|
||||
var newModel = entriesModel.slice();
|
||||
var item = newModel.splice(fromIndex, 1)[0];
|
||||
newModel.splice(toIndex, 0, item);
|
||||
entriesModel = newModel;
|
||||
saveEntries();
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (_activeDialog && _activeDialog.close) {
|
||||
var dialog = _activeDialog;
|
||||
_activeDialog = null;
|
||||
dialog.close();
|
||||
dialog.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
function openEntrySettingsDialog(index) {
|
||||
if (index < 0 || index >= entriesModel.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var entry = entriesModel[index];
|
||||
var component = Qt.createComponent(Quickshell.shellDir + "/Modules/Panels/Settings/Tabs/SessionMenu/SessionMenuEntrySettingsDialog.qml");
|
||||
|
||||
function instantiateAndOpen() {
|
||||
if (root._activeDialog) {
|
||||
root._activeDialog.close();
|
||||
root._activeDialog.destroy();
|
||||
root._activeDialog = null;
|
||||
}
|
||||
|
||||
var dialog = component.createObject(Overlay.overlay, {
|
||||
"entryIndex": index,
|
||||
"entryData": entry,
|
||||
"entryId": entry.id,
|
||||
"entryText": entry.text
|
||||
});
|
||||
|
||||
if (dialog) {
|
||||
root._activeDialog = dialog;
|
||||
dialog.updateEntryProperties.connect((idx, properties) => {
|
||||
root.updateEntry(idx, properties);
|
||||
});
|
||||
dialog.closed.connect(() => {
|
||||
if (root._activeDialog === dialog) {
|
||||
root._activeDialog = null;
|
||||
dialog.destroy();
|
||||
}
|
||||
});
|
||||
dialog.open();
|
||||
} else {
|
||||
Logger.e("SessionMenuTab", "Failed to create entry settings dialog");
|
||||
}
|
||||
}
|
||||
|
||||
if (component.status === Component.Ready) {
|
||||
instantiateAndOpen();
|
||||
} else if (component.status === Component.Error) {
|
||||
Logger.e("SessionMenuTab", "Error loading entry settings dialog:", component.errorString());
|
||||
} else {
|
||||
component.statusChanged.connect(function () {
|
||||
if (component.status === Component.Ready) {
|
||||
instantiateAndOpen();
|
||||
} else if (component.status === Component.Error) {
|
||||
Logger.e("SessionMenuTab", "Error loading entry settings dialog:", component.errorString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
entriesModel = [];
|
||||
|
||||
// Add the entries available in settings
|
||||
for (var i = 0; i < Settings.data.sessionMenu.powerOptions.length; i++) {
|
||||
const settingEntry = Settings.data.sessionMenu.powerOptions[i];
|
||||
|
||||
for (var j = 0; j < entriesDefault.length; j++) {
|
||||
if (settingEntry.action === entriesDefault[j].id) {
|
||||
var entry = entriesDefault[j];
|
||||
entry.enabled = settingEntry.enabled;
|
||||
// Default countdownEnabled to true for backward compatibility
|
||||
entry.countdownEnabled = settingEntry.countdownEnabled !== undefined ? settingEntry.countdownEnabled : true;
|
||||
// Load custom command if defined
|
||||
entry.command = settingEntry.command || "";
|
||||
entry.keybind = settingEntry.keybind || "";
|
||||
entriesModel.push(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add any missing entries from default
|
||||
for (var i = 0; i < entriesDefault.length; i++) {
|
||||
var found = false;
|
||||
for (var j = 0; j < entriesModel.length; j++) {
|
||||
if (entriesModel[j].id === entriesDefault[i].id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
var entry = entriesDefault[i];
|
||||
// Default countdownEnabled to true for new entries
|
||||
entry.countdownEnabled = true;
|
||||
// Default command to empty string for new entries
|
||||
entry.command = "";
|
||||
entry.keybind = "";
|
||||
entriesModel.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
saveEntries();
|
||||
}
|
||||
|
||||
NTabBar {
|
||||
id: subTabBar
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginM
|
||||
distributeEvenly: true
|
||||
currentIndex: tabView.currentIndex
|
||||
|
||||
NTabButton {
|
||||
text: I18n.tr("common.general")
|
||||
tabIndex: 0
|
||||
checked: subTabBar.currentIndex === 0
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.actions")
|
||||
tabIndex: 1
|
||||
checked: subTabBar.currentIndex === 1
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Style.marginL
|
||||
}
|
||||
|
||||
NTabView {
|
||||
id: tabView
|
||||
currentIndex: subTabBar.currentIndex
|
||||
|
||||
GeneralSubTab {}
|
||||
ActionsSubTab {
|
||||
entriesModel: root.entriesModel
|
||||
updateEntry: root.updateEntry
|
||||
reorderEntries: root.reorderEntries
|
||||
openEntrySettingsDialog: root.openEntrySettingsDialog
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user