Files
komplex-hub/build/qml/KomplexHubContent/pages/WallpaperSettingsPage.qml
T
2026-06-02 15:11:36 -04:00

668 lines
25 KiB
QML

/*
* Komplex Wallpaper Engine
* Copyright (C) 2025 @DigitalArtifex | github.com/DigitalArtifex
*
* config.qml
*
* This component provides a configuration interface for the Komplex Wallpaper Engine,
* allowing users to customize shader settings, channel configurations, and other
* parameters related to the wallpaper engine.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>
*/
// pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs
import QtQuick.Layouts
//import org.kde.kirigami as Kirigami
//import org.kde.plasma.core as PlasmaCore
import QtCore
import Qt.labs.folderlistmodel 2.15
import KomplexHub
import KomplexHub.Controls
import KomplexHubPlugin
//import com.github.digitalartifex.komplex 1.0 as Komplex
Item
{
SettingsManager {
id: manager
onError: (title, message) => {
console.log(title + ": " + message)
}
}
id: root
property alias cfg_pauseMode: pauseModeCombo.currentIndex
property alias cfg_isPaused: runningCombo.checked
property alias cfg_shaderSpeed: speedSlider.value
property alias cfg_mouseSpeedBias: mouseBiasSlider.value
property alias cfg_mouseAllowed: mouseEnableButton.checked
property bool cfg_infoPlasma6Preview_dismissed
property bool cfg_warningResources_dismissed
property bool cfg_emergencyHelp_dismissed
property bool cfg_infoiChannelSettings_dismissed
property alias cfg_checkActiveScreen: activeScreenOnlyCheckbox.checked
property alias cfg_excludeWindows: excludeWindows.windows
property alias cfg_running: runningCombo.checked
property alias cfg_resolution_x: resolutionXField.value
property alias cfg_resolution_y: resolutionYField.value
property alias cfg_framerate_limit: frameRateField.value
property bool cfg_shader_updated
property string shaderPackage: ""
property int shaderPackageIndex: 0
property real shaderSpeed: 1.0
property int resolutionX: 1080
property int resolution: 1920
property bool enableMouseTracking: true
property real mouseTrackingBias: 0.5
Rectangle {
anchors.fill: parent
color: palette.base
clip: true
ColumnLayout {
anchors.fill: parent
Text {
text: qsTr("Wallpaper")
font: Constants.h2Font
color: palette.text
}
Text {
text: manager.shaderPack
}
ComboBox
{
property string shader
Layout.fillWidth: true
id: selectedShaderPack
model: manager.availableShaderPacks
delegate: Component
{
id: packListDelegate
ItemDelegate
{
width: parent ? parent.width : 0
text: modelData
}
}
textRole: "modelData"
currentIndex: manager.shaderPackIndex
displayText: currentIndex === -1 ? "Custom File" : currentText.replace("_", " ").charAt(0).toUpperCase() + currentText.replace("_", " ").slice(1)
// onCurrentTextChanged:
// {
// root.cfg_shader_package_index = currentIndex;
// if (root.cfg_shader_package_index === -1)
// return;
// var source = currentText
// shaderPackModel.loadMetadata(source)
// root.cfg_shader_package = "file://" + shaderPackModel.path(source)
// }
}
RowLayout
{
Layout.fillWidth: true
visible: true
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Shader Pack:")
// ComboBox
// {
// property string shader
// Layout.fillWidth: true
// id: selectedShaderPack
// //model: shaderPackModel.availableShaderPacks
// delegate: Component
// {
// id: packListDelegate
// ItemDelegate
// {
// width: parent ? parent.width : 0
// text: modelData
// }
// }
// textRole: "modelData"
// currentIndex: root.cfg_shader_package_index
// displayText: currentIndex === -1 ? "Custom File" : currentText.replace("_", " ").charAt(0).toUpperCase() + currentText.replace("_", " ").slice(1)
// onCurrentTextChanged:
// {
// root.cfg_shader_package_index = currentIndex;
// if (root.cfg_shader_package_index === -1)
// return;
// var source = currentText
// shaderPackModel.loadMetadata(source)
// root.cfg_shader_package = "file://" + shaderPackModel.path(source)
// }
// }
FileDialog
{
id: packDialog
fileMode: FileDialog.OpenFile
title: i18nd("@dialog_title:choose_shader", "Choose a shader")
// will accept and auto convert .frag in the near future
nameFilters: ["Shader Package files (*.json)", "All files (*)"]
visible: false
currentFolder: "file://" + shaderPackModel.shaderPackInstallPath
onAccepted:
{
root.cfg_shader_package_index = -1;
root.cfg_shader_package = selectedFile;
shaderPackModel.loadMetadataFromFile(selectedFile)
}
}
}
// Kirigami.Separator
// {
// Kirigami.FormData.isSection: false
// }
// TabBar
// {
// Layout.topMargin: 6
// Layout.fillWidth: true
// id: navBar
// width: parent.width
// TabButton {
// height: 36
// text: root.cfg_komplex_mode === 0 ? qsTr("Channels") : qsTr("Information")
// }
// TabButton {
// height: 36
// text: qsTr("Settings")
// }
// TabButton {
// height: 36
// text: qsTr("Extra Settings")
// }
// }
// RowLayout
// {
// Layout.fillWidth: true
// Kirigami.InlineMessage
// {
// id: warningResources
// Layout.fillWidth: true
// type: Kirigami.MessageType.Warning
// text: qsTr("Some shaders might consume more power and resources than others, beware!")
// showCloseButton: true
// visible: !root.cfg_warningResources_dismissed
// onVisibleChanged: () =>
// {
// root.cfg_warningResources_dismissed = true;
// }
// }
// }
Text {
text: qsTr("Render Resolution")
font: Constants.h2Font
color: palette.text
}
RowLayout
{
visible: navBar.currentIndex === 1
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Resolution:")
Text
{
color: palette.text
text: "X"
verticalAlignment: Text.AlignVCenter
}
TextField
{
property int value
id: resolutionXField
inputMethodHints: Qt.ImhFormattedNumbersOnly
horizontalAlignment: Text.AlignRight
Layout.preferredWidth: Kirigami.Units.gridUnit * 4
text: value
onEditingFinished: () =>
{
value = parseInt(text)
}
Keys.onPressed: (event) =>
{
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
{
resolutionXField.focus = false; // Unfocus the TextField
event.accepted = true; // Prevent further propagation of the key event
}
}
background: Rectangle
{
color: resolutionXField.activeFocus ? palette.base : "transparent"
border.color: resolutionXField.activeFocus ? palette.highlight : "transparent"
border.width: 1
radius: 4
anchors.fill: resolutionXField
anchors.margins: -2
}
}
Text
{
color: palette.text
text: "Y"
verticalAlignment: Text.AlignVCenter
}
TextField
{
property int value
id: resolutionYField
inputMethodHints: Qt.ImhFormattedNumbersOnly
horizontalAlignment: Text.AlignRight
Layout.preferredWidth: Kirigami.Units.gridUnit * 4
text: value
onEditingFinished: () =>
{
value = parseInt(text)
}
Keys.onPressed: (event) =>
{
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
{
resolutionYField.focus = false; // Unfocus the TextField
event.accepted = true; // Prevent further propagation of the key event
}
}
background: Rectangle
{
color: resolutionYField.activeFocus ? palette.base : "transparent"
border.color: resolutionYField.activeFocus ? palette.highlight : "transparent"
border.width: 1
radius: 4
anchors.fill: resolutionYField
anchors.margins: -2
}
}
}
RowLayout
{
visible: navBar.currentIndex === 1
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Frame Rate:")
TextField
{
property int value
id: frameRateField
inputMethodHints: Qt.ImhFormattedNumbersOnly
Layout.preferredWidth: Kirigami.Units.gridUnit * 4
onEditingFinished: () =>
{
value = parseInt(text)
}
Keys.onPressed: (event) =>
{
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
{
frameRateField.focus = false; // Unfocus the TextField
event.accepted = true; // Prevent further propagation of the key event
}
}
background: Rectangle
{
color: frameRateField.activeFocus ? palette.base : "transparent"
border.color: frameRateField.activeFocus ? palette.highlight : "transparent"
border.width: 1
radius: 4
anchors.fill: frameRateField
anchors.margins: -2
}
Component.onCompleted: () =>
{
text = value
}
}
}
ColumnLayout
{
visible: navBar.currentIndex === 1
id: speedLayout
Layout.fillWidth: true
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Shader speed:")
Slider
{
id: speedSlider
Layout.fillWidth: true
from: -4.0
to: 4.0
stepSize: 0.01
onValueChanged: shaderSpeedField.text = String(value.toFixed(2));
}
LineEdit
{
id: shaderSpeedField
//inputMethodHints: Qt.ImhFormattedNumbersOnly
//horizontalAlignment: Text.AlignRight
Layout.preferredWidth: 128
// onEditingFinished: () =>
// {
// let inputValue = parseFloat(text);
// if (isNaN(inputValue) || inputValue < speedSlider.from)
// inputValue = speedSlider.from;
// else if (inputValue > speedSlider.to)
// inputValue = speedSlider.to;
// text = inputValue.toFixed(2);
// speedSlider.value = inputValue;
// }
Keys.onPressed: (event) =>
{
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
{
shaderSpeedField.focus = false; // Unfocus the TextField
event.accepted = true; // Prevent further propagation of the key event
}
}
// background: Rectangle
// {
// color: shaderSpeedField.activeFocus ? palette.base : "transparent"
// border.color: shaderSpeedField.activeFocus ? palette.highlight : "transparent"
// border.width: 1
// radius: 4
// anchors.fill: shaderSpeedField
// anchors.margins: -2
// }
}
}
ComboBox
{
visible: navBar.currentIndex === 1
id: pauseModeCombo
//Kirigami.FormData.label: i18nd("@buttonGroup:pause_mode", "Pause:")
model: [
{
'label': i18nd("@option:pause_mode", "Maximized or full-screen windows")
},
{
'label': i18nd("@option:pause_mode", "Active window is present")
},
{
'label': i18nd("@option:pause_mode", "At least one window is shown")
},
{
'label': i18nd("@option:pause_mode", "Never")
}
]
textRole: "label"
onCurrentIndexChanged: root.cfg_pauseMode = currentIndex
currentIndex: root.cfg_pauseMode
}
CheckBox
{
visible: navBar.currentIndex === 1
id: activeScreenOnlyCheckbox
//Kirigami.FormData.label: i18nd("@checkbox:screen_filter", "Filter:")
text: i18n("Only check for windows in active screen")
}
TextField
{
visible: navBar.currentIndex === 1
id: excludeWindows
property var windows: []
width: Kirigami.Units.gridUnit * 11
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Exclude windows:")
text: windows.join(",")
onEditingFinished: () =>
{
windows = excludeWindows.text.trim().replace(/\s+/g, "").split(",");
}
ToolTip.visible: hovered
ToolTip.text: qsTr("A comma-separated list of fully-qualified App-IDs to exclude their windows from triggering pause mode.")
}
CheckBox
{
visible: navBar.currentIndex === 1
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", cfg_isPaused ? "Playing" : "Paused")
id: runningCombo
checked: root.cfg_running
text: i18n("Play/Pause the shader")
onCheckedChanged: () =>
{
// wallpaper.configuration.running = checked;
root.cfg_running = checked;
}
}
RowLayout
{
visible: navBar.currentIndex === 2
id: mouseLayout
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Mouse allowed:")
Button
{
id: mouseEnableButton
icon.name: checked ? "followmouse-symbolic" : "hidemouse-symbolic"
text: i18nd("@button:toggle_use_mouse", checked ? "Enabled" : "Disabled")
checkable: true
ToolTip.visible: hovered
ToolTip.text: qsTr("Enabling this will allow the shader to interact with the cursor but will prevent interaction with desktop elements")
}
}
RowLayout
{
id: mouseBiasLayout
visible: root.cfg_mouseAllowed && navBar.currentIndex === 2
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Mouse bias:")
ColumnLayout
{
Slider
{
id: mouseBiasSlider
Layout.preferredWidth: Kirigami.Units.gridUnit * 16
from: 0.0
to: 4.0
stepSize: 0.01
value: root.cfg_mouseSpeedBias ? root.cfg_mouseSpeedBias : 1.0
onValueChanged: () =>
{
mouseBiasField.text = String(value.toFixed(2));
// wallpaper.configuration.mouseBias = mouseBiasField.text;
root.cfg_mouseSpeedBias = mouseBiasField.text;
}
}
}
ColumnLayout
{
TextField
{
id: mouseBiasField
text: root.cfg_mouseSpeedBias ? String(root.cfg_mouseSpeedBias.toFixed(2)) : "1.00"
inputMethodHints: Qt.ImhFormattedNumbersOnly
Layout.preferredWidth: Kirigami.Units.gridUnit * 3
onEditingFinished: () =>
{
let inputValue = parseFloat(text);
if (isNaN(inputValue) || inputValue < mouseBiasSlider.from)
inputValue = mouseBiasSlider.from;
else if (inputValue > mouseBiasSlider.to)
inputValue = mouseBiasSlider.to;
text = inputValue.toFixed(2);
mouseBiasSlider.value = inputValue;
// wallpaper.configuration.mouseBias = inputValue;
root.cfg_mouseSpeedBias = inputValue;
}
Keys.onPressed: (event) =>
{
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter)
{
mouseBiasField.focus = false; // Unfocus the TextField
event.accepted = true; // Prevent further propagation of the key event
}
}
background: Rectangle
{
color: mouseBiasField.activeFocus ? palette.base : "transparent"
border.color: mouseBiasField.activeFocus ? palette.highlight : "transparent"
border.width: 1
radius: 4
anchors.fill: mouseBiasField
anchors.margins: -2
}
}
}
}
Button
{
visible: navBar.currentIndex === 2
id: kofiButton
Layout.preferredWidth: Kirigami.Units.gridUnit * 5
Layout.preferredHeight: Kirigami.Units.gridUnit * 3
contentItem: RowLayout
{
AnimatedImage
{
source: "icons/kofi.gif"
sourceSize.width: 36
sourceSize.height: 36
fillMode: Image.Pad
horizontalAlignment: Image.AlignLeft
transform: Translate
{
x: 8
}
}
Text
{
text: i18nd("@button:kofi", "Kofi")
horizontalAlignment: Text.AlignHCenter
color: palette.text
transform: Translate
{
x: -8
}
}
}
onClicked: () =>
{
Qt.openUrlExternally("https://ko-fi.com/digitalartifex");
}
}
RowLayout
{
visible: root.cfg_komplex_mode === 1 && navBar.currentIndex === 0
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Author:")
Text
{
Layout.preferredWidth: Kirigami.Units.gridUnit * 11
text: shaderPackModel.metadata.author
horizontalAlignment: Text.AlignLeft
color: palette.text
}
}
RowLayout
{
visible: root.cfg_komplex_mode === 1 && navBar.currentIndex === 0
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Description:")
Text
{
Layout.preferredWidth: Kirigami.Units.gridUnit * 16
text: shaderPackModel.metadata.description
horizontalAlignment: Text.AlignLeft
color: palette.text
wrapMode: Text.WordWrap
maximumLineCount: 2
elide: Text.ElideRight
}
}
RowLayout
{
visible: root.cfg_komplex_mode === 1 && navBar.currentIndex === 0
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "License:")
Text
{
Layout.preferredWidth: Kirigami.Units.gridUnit * 11
text: shaderPackModel.metadata.license
horizontalAlignment: Text.AlignLeft
color: palette.text
}
}
RowLayout
{
visible: root.cfg_komplex_mode === 1 && navBar.currentIndex === 0
//Kirigami.FormData.label: i18nd("com.github.digitalartifex.komplex", "Version:")
Text
{
Layout.preferredWidth: Kirigami.Units.gridUnit * 11
text: shaderPackModel.metadata.version
horizontalAlignment: Text.AlignLeft
color: palette.text
}
}
}
}
}