You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
GlosSI/GlosSIConfig/qml/ShortcutProps.qml

808 lines
37 KiB
QML

/*
Copyright 2021-2022 Peter Repukat - FlatspotSoftware
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import QtQuick 6.2
import QtQuick.Controls 6.2
import QtQuick.Layouts 6.2
import QtQuick.Controls.Material 6.2
import QtQuick.Dialogs 6.2
Item {
id: propsContent
anchors.fill: parent
property alias fileDialog: fileDialog
property alias uwpSelectDialog: uwpSelectDialog
signal cancel()
signal done(var shortcut)
property var shortcutInfo: ({})
function resetInfo() {
shortcutInfo = ({
"controller": {
"maxControllers": 1,
"emulateDS4": false,
"allowDesktopConfig": false
},
"devices": {
"hideDevices": true,
"realDeviceIds": false
},
"icon": null,
"launch": {
"closeOnExit": true,
"launch": false,
"launchAppArgs": null,
"launchPath": null,
"waitForChildProcs": true
},
"name": null,
"version": 1,
"window": {
"disableOverlay": false,
"maxFps": null,
"scale": null,
"windowMode": false
},
"extendedLogging": false
})
}
Component.onCompleted: function() {
resetInfo()
}
onShortcutInfoChanged: function() {
nameInput.text = shortcutInfo.name || ""
if (extendedLogging) {
extendedLogging.checked = shortcutInfo.extendedLogging || false
}
launchApp.checked = shortcutInfo.launch.launch
pathInput.text = shortcutInfo.launch.launchPath || ""
argsInput.text = shortcutInfo.launch.launchAppArgs || ""
closeOnExit.checked = shortcutInfo.launch.closeOnExit
waitForChildren.checked = shortcutInfo.launch.waitForChildProcs
hideDevices.checked = shortcutInfo.devices.hideDevices
realDeviceIds.checked = shortcutInfo.devices.realDeviceIds
windowMode.checked = shortcutInfo.window.windowMode
disableOverlayCheckbox.checked = shortcutInfo.window.disableOverlay
scaleSpinBox.value = shortcutInfo.window.scale
maxFPSSpinBox.value = shortcutInfo.window.maxFps
maxControllersSpinBox.value = shortcutInfo.controller.maxControllers
allowDesktopConfig.checked = shortcutInfo.controller.allowDesktopConfig
emulateDS4.checked = shortcutInfo.controller.emulateDS4
}
Flickable {
id: flickable
anchors.margins: 0
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
clip: true
ScrollBar.vertical: ScrollBar {
}
contentWidth: propscolumn.width
contentHeight: propscolumn.height
flickableDirection: Flickable.VerticalFlick
Column {
id: propscolumn
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 32
spacing: 4
Item {
id: topspacing
width: 1
height: 32
}
Item {
id: namewrapper
width: parent.width / 3
height: 64
Label {
anchors.left: parent.left
anchors.leftMargin: 4
id: nameLabel
font.bold: true
text: qsTr("Name")
}
FluentTextInput {
width: parent.width
anchors.top: nameLabel.bottom
anchors.topMargin: 4
id: nameInput
placeholderText: qsTr("...")
text: shortcutInfo.name
onTextChanged: shortcutInfo.name = text
validator: RegularExpressionValidator { regularExpression: /([0-z]|\s|.)+/gm }
}
}
Item {
width: 1
height: 8
}
RPane {
width: parent.width
radius: 4
Material.elevation: 32
bgOpacity: 0.97
Column {
width: parent.width
height: parent.height
spacing: 4
Row {
spacing: 32
width: parent.width
CheckBox {
id: launchApp
text: qsTr("Launch app")
checked: shortcutInfo.launch.launch
onCheckedChanged: function() {
shortcutInfo.launch.launch = checked
if (checked) {
if (closeOnExit) {
closeOnExit.enabled = true;
if (closeOnExit.checked) {
waitForChildren.enabled = true;
}
}
allowDesktopConfig.enabled = true;
} else {
waitForChildren.enabled = false;
closeOnExit.enabled = false;
allowDesktopConfig.enabled = false;
}
}
}
}
Item {
width: 1
height: 8
}
RowLayout {
id: launchlayout
spacing: 4
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 32
anchors.rightMargin: 32
Image {
id: maybeIcon
source: shortcutInfo.icon
? shortcutInfo.icon.endsWith(".exe")
? "image://exe/" + shortcutInfo.icon
: "file:///" + shortcutInfo.icon
: ''
Layout.preferredWidth: 48
Layout.preferredHeight: 48
visible: shortcutInfo.icon
Layout.alignment: Qt.AlignVCenter
}
Item {
Layout.preferredWidth: 8
Layout.preferredHeight: 8
visible: shortcutInfo.icon
}
Item {
Layout.preferredWidth: parent.width / 2
Layout.fillWidth: true
height: 64
Label {
anchors.left: parent.left
anchors.leftMargin: 4
id: pathLabel
font.bold: true
text: qsTr("Path")
}
FluentTextInput {
width: parent.width
anchors.top: pathLabel.bottom
anchors.topMargin: 4
id: pathInput
placeholderText: qsTr("...")
enabled: launchApp.checked
text: shortcutInfo.launch.launchPath || ""
onTextChanged: shortcutInfo.launch.launchPath = text
}
}
Button {
Layout.preferredWidth: 64
Layout.alignment: Qt.AlignBottom
text: qsTr("...")
onClicked: fileDialog.open();
}
Button {
Layout.preferredWidth: 64
Layout.alignment: Qt.AlignBottom
text: qsTr("UWP")
visible: uiModel.isWindows
onClicked: uwpSelectDialog.open();
}
Item {
height: 1
Layout.preferredWidth: 12
}
Item {
Layout.preferredWidth: parent.width / 2.5
height: 64
Label {
anchors.left: parent.left
anchors.leftMargin: 4
id: argslabel
font.bold: true
text: qsTr("Launch Arguments")
}
FluentTextInput {
width: parent.width
anchors.top: argslabel.bottom
anchors.topMargin: 4
id: argsInput
enabled: launchApp.checked
text: shortcutInfo.launch.launchAppArgs
onTextChanged: shortcutInfo.launch.launchAppArgs = text
}
}
}
}
}
Item {
width: 1
height: 8
}
CollapsiblePane {
radius: 4
Material.elevation: 32
bgOpacity: 0.97
title: qsTr("Advanced")
content:
Column {
spacing: 16
RPane {
width: parent.width
radius: 4
Material.elevation: 32
bgOpacity: 0.97
height: advancedLaunchCol.height + 24
Column {
id: advancedLaunchCol
spacing: 4
height: advancedLaunchedRow.height
Row {
id: advancedLaunchedRow
spacing: 32
width: parent.width
height: closeOnExitCol.height
Column {
id: closeOnExitCol
spacing: 2
CheckBox {
id: closeOnExit
text: qsTr("Close when launched app quits")
checked: shortcutInfo.launch.closeOnExit
onCheckedChanged: function() {
shortcutInfo.launch.closeOnExit = checked
if (checked) {
waitForChildren.enabled = true;
} else {
waitForChildren.enabled = false;
}
}
}
Label {
text: qsTr("Recommended to disable for launcher-games")
wrapMode: Text.WordWrap
width: parent.width
leftPadding: 32
topPadding: -8
}
CheckBox {
id: waitForChildren
text: qsTr("Wait for child processes")
checked: shortcutInfo.launch.waitForChildProcs
onCheckedChanged: function(){
shortcutInfo.launch.waitForChildProcs = checked
}
}
}
Column {
spacing: 2
CheckBox {
id: allowDesktopConfig
text: qsTr("Allow desktop-config")
checked: shortcutInfo.controller.allowDesktopConfig
onCheckedChanged: function(){
shortcutInfo.controller.allowDesktopConfig = checked
}
}
Label {
text: qsTr("Allow desktop-config if launched application is not focused")
leftPadding: 32
topPadding: -8
}
}
}
}
}
Row {
spacing: 16
width: parent.width
RPane {
width: parent.width / 2 - 8
height: 248
radius: 4
Material.elevation: 32
bgOpacity: 0.97
Column {
spacing: 0
width: parent.width
Row {
CheckBox {
id: hideDevices
text: qsTr("Hide (Real) Controllers")
checked: shortcutInfo.devices.hideDevices
onCheckedChanged: shortcutInfo.devices.hideDevices = checked
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("Hide (Real) Controllers")
helpInfoDialog.text =
qsTr("Hides real game controllers from the system\nThis may prevent doubled inputs")
+ "\n"
+ qsTr("You can change this setting and which devices are hidden in the GlosSI overlay")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
Item {
width: 1
height: 4
}
Row {
CheckBox {
id: realDeviceIds
text: qsTr("Use real device (USB)-IDs")
checked: shortcutInfo.devices.realDeviceIds
onCheckedChanged: shortcutInfo.devices.realDeviceIds = checked
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("Use real device (USB)-IDs")
helpInfoDialog.text =
qsTr("Only enable if input's are not recognized by the game")
+ "\n"
+ qsTr("If enabled, device-hiding won't work.\nUse the \"Max. Controller count\" setting!")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
Item {
width: 1
height: 4
}
Row {
CheckBox {
id: emulateDS4
text: qsTr("Emulate DS4")
checked: shortcutInfo.controller.emulateDS4 || false
onCheckedChanged: shortcutInfo.controller.emulateDS4 = checked
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("Emulate DS4")
helpInfoDialog.text =
qsTr("Emulates a DS4 instead of X360 Pad")
+ "\n"
qsTr("for usage with, for example, PSNow")
+ "\n"
+ qsTr("If enabled you have to disable \"Playstation Configuration support\" in Steam")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
Item {
width: 1
height: 4
}
Row {
leftPadding: 16
Label {
text: qsTr("Max. emulated controllers")
topPadding: 16
}
SpinBox {
id: maxControllersSpinBox
width: 128
editable: true
value: shortcutInfo.controller.maxControllers
from: 0
to: 4
onValueChanged: shortcutInfo.controller.maxControllers = value
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("Max. emulated controllers")
helpInfoDialog.text =
qsTr("GlosSI will only provide [NUMBER] of controllers")
+ "\n"
+ qsTr("Required to set to actually connected controller count when using \"real device IDs\" ")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
}
}
RPane {
width: parent.width / 2 - 8
height: 248
radius: 4
Material.elevation: 32
bgOpacity: 0.97
Column {
spacing: 0
width: parent.width
Row {
CheckBox {
id: windowMode
text: qsTr("Steam/GlosSI overlay as separate window")
checked: shortcutInfo.window.windowMode
onCheckedChanged: shortcutInfo.window.windowMode = checked
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("Steam/GlosSI overlay as separate window")
helpInfoDialog.text =
qsTr("Doesn't show overlay on top, but as separate window")
+ "\n"
+ qsTr("Use if blackscreen-issues are encountered.")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
Item {
width: 1
height: 4
}
Row {
CheckBox {
id: disableOverlayCheckbox
text: qsTr("Disable Steam/GlosSI overlay")
checked: shortcutInfo.window.disableOverlay
onCheckedChanged: shortcutInfo.window.disableOverlay = checked
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("Disable Steam/GlosSI overlay")
helpInfoDialog.text =
qsTr("Only controller emulation - No extra window")
+ "\n"
+ qsTr("Might help with Steam remote play.")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
Item {
width: 1
height: 4
}
Row {
leftPadding: 16
Label {
text: qsTr("GlosSI-Overlay scale")
topPadding: 16
}
SpinBox {
id: scaleSpinBox
width: 172
from: -100
value: shortcutInfo.window.scale * 100 || 0
to: 350
stepSize: 10
editable: true
property int decimals: 2
property real realValue: value / 100
validator: DoubleValidator {
bottom: Math.min(scaleSpinBox.from, scaleSpinBox.to)
top: Math.max(scaleSpinBox.from, scaleSpinBox.to)
}
textFromValue: function(value, locale) {
return Number(value / 100).toLocaleString(locale, 'f', scaleSpinBox.decimals)
}
valueFromText: function(text, locale) {
return Number.fromLocaleString(locale, text) * 100
}
onValueChanged: function() {
if (value <= 0) {
shortcutInfo.window.scale = null
return
}
shortcutInfo.window.scale = value / 100
}
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("GloSI-Overlay scaling")
helpInfoDialog.text =
qsTr("Scales the elements of the GlosSI-Overlay (not Steam Overlay)")
+ "\n"
+ qsTr(" <= 0.0 to use auto-detection")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
Item {
width: 1
height: 4
}
Row {
leftPadding: 16
Label {
text: qsTr("Max. Overlay FPS")
topPadding: 16
}
SpinBox {
id: maxFPSSpinBox
width: 172
from: -1
value: shortcutInfo.window.maxFps || 0
to: 244
stepSize: 5
editable: true
onValueChanged: function() {
if (value <= 0) {
shortcutInfo.window.maxFps = null
return
}
shortcutInfo.window.maxFps = value
}
}
RoundButton {
onClicked: () => {
helpInfoDialog.titleText = qsTr("Max. Overlay FPS")
helpInfoDialog.text =
qsTr("Restricts the FPS of the overlay to the given value")
+ "\n"
+ qsTr(" <= 0.0 to use screen refresh rate")
helpInfoDialog.open()
}
width: 48
height: 48
Material.elevation: 0
anchors.topMargin: 16
Image {
anchors.centerIn: parent
source: "qrc:/svg/help_outline_white_24dp.svg"
width: 24
height: 24
}
}
}
}
}
}
RPane {
width: parent.width
radius: 4
Material.elevation: 32
bgOpacity: 0.97
Column {
spacing: 4
Row {
Row {
CheckBox {
id: extendedLogging
text: qsTr("Extended Logging")
checked: shortcutInfo.extendedLogging
onCheckedChanged: shortcutInfo.extendedLogging = checked
}
// RoundButton {
// onClicked: () => {
// helpInfoDialog.titleText = qsTr("Hide (Real) Controllers")
// helpInfoDialog.text =
// qsTr("Hides real game controllers from the system\nThis may prevent doubled inputs")
// + "\n"
// + qsTr("You can change this setting and which devices are hidden in the GlosSI overlay")
// helpInfoDialog.open()
// }
// width: 48
// height: 48
// Material.elevation: 0
// anchors.topMargin: 16
// Image {
// anchors.centerIn: parent
// source: "qrc:/svg/help_outline_white_24dp.svg"
// width: 24
// height: 24
// }
// }
}
}
}
}
}
}
Item {
id: bottomspacing
width: 1
height: 32
}
}
}
Row {
spacing: 8
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.margins: 24
anchors.bottomMargin: 16
Button {
text: qsTr("Cancel")
onClicked: function() {
cancel()
}
}
Button {
text: qsTr("Save")
highlighted: true
enabled: nameInput.acceptableInput
onClicked: function() {
done(shortcutInfo)
}
}
}
FileDialog {
id: fileDialog
title: qsTr("Please choose a Program to Launch")
nameFilters: uiModel.isWindows ? ["Executable files (*.exe *.bat *.ps1)"] : []
onAccepted: {
if (fileDialog.selectedFile != null) {
pathInput.text = fileDialog.selectedFile.toString().replace("file:///", "")
if (nameInput.text == "") {
nameInput.text = pathInput.text.replace(/.*(\\|\/)/,"").replace(/\.[0-z]*$/, "")
shortcutInfo.icon = nameInput.text
}
launchApp.checked = true
}
}
onRejected: {
}
}
UWPSelectDialog {
id: uwpSelectDialog
onConfirmed: function(modelData) {
if (nameInput.text == "") {
nameInput.text = modelData.AppName
}
if (modelData.IconPath) {
shortcutInfo.icon = modelData.IconPath
}
pathInput.text = modelData.AppUMId
launchApp.checked = true
}
}
InfoDialog {
id: helpInfoDialog
titleText: qsTr("")
text: qsTr("")
extraButton: false
extraButtonText: qsTr("")
onConfirmedExtra: function(data) {
}
}
}