Merge pull request #1385 from Armored-Dragon/feature/SettingsRebase2
New Graphics SettingsUI
|
@ -1,898 +0,0 @@
|
|||
//
|
||||
// GraphicsSettings.qml
|
||||
// qml\hifi\dialogs\graphics
|
||||
//
|
||||
// Created by Zach Fox on 2019-07-10
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
// Copyright 2024 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.12
|
||||
import stylesUit 1.0 as HifiStylesUit
|
||||
import controlsUit 1.0 as HifiControlsUit
|
||||
import "qrc:////qml//controls" as HifiControls
|
||||
import PerformanceEnums 1.0
|
||||
|
||||
Flickable {
|
||||
HifiStylesUit.HifiConstants { id: hifi; }
|
||||
|
||||
contentHeight: graphicsSettingsColumnLayout.height;
|
||||
|
||||
ScrollBar.vertical : ScrollBar {
|
||||
policy: ScrollBar.AlwaysOn
|
||||
visible: true
|
||||
width: 20
|
||||
background: Rectangle {
|
||||
color: hifi.colors.tableScrollBackgroundDark
|
||||
}
|
||||
}
|
||||
|
||||
id: root;
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
id: graphicsSettingsColumnLayout
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 26
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 26
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: HMD.active ? 80 : 0
|
||||
spacing: 8
|
||||
|
||||
ColumnLayout {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.topMargin: 18
|
||||
spacing: 0
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
text: "GRAPHICS SETTINGS"
|
||||
Layout.maximumWidth: parent.width
|
||||
height: 30
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 10
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceLowPower
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Low Power"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.LOW_POWER
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.LOW_POWER);
|
||||
root.refreshAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceLow
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Low"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.LOW
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.LOW);
|
||||
root.refreshAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceMedium
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Medium"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.MID
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.MID);
|
||||
root.refreshAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceHigh
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "High"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.HIGH
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.HIGH);
|
||||
root.refreshAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: performanceCustom
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Custom"
|
||||
checked: Performance.getPerformancePreset() === PerformanceEnums.CUSTOM
|
||||
onClicked: {
|
||||
Performance.setPerformancePreset(PerformanceEnums.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 10
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: worldDetailHeader
|
||||
text: "Target frame rate"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: worldDetailModel
|
||||
|
||||
ListElement {
|
||||
text: "High Frame Rate/Low Detail"
|
||||
}
|
||||
ListElement {
|
||||
text: "Medium Frame Rate/Medium Detail"
|
||||
}
|
||||
ListElement {
|
||||
text: "Low Frame Rate/High Detail"
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: worldDetailDropdown
|
||||
enabled: performanceCustom.checked
|
||||
anchors.left: worldDetailHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
width: 280
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: worldDetailModel
|
||||
currentIndex: -1
|
||||
|
||||
function refreshWorldDetailDropdown() {
|
||||
worldDetailDropdown.currentIndex = LODManager.worldDetailQuality;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
worldDetailDropdown.refreshWorldDetailDropdown();
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
LODManager.worldDetailQuality = currentIndex;
|
||||
worldDetailDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.topMargin: 20
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: renderingEffectsHeader
|
||||
text: "Rendering Effects"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.left: renderingEffectsHeader.right
|
||||
anchors.leftMargin: 20
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
enabled: performanceCustom.checked
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: renderingEffectsDisabled
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Disabled"
|
||||
checked: Render.renderMethod === 1
|
||||
onClicked: {
|
||||
Render.renderMethod = 1; // "FORWARD"
|
||||
//refreshRenderingEffectCheckboxes();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.RadioButton {
|
||||
id: renderingEffectsEnabled
|
||||
enabled: PlatformInfo.isRenderMethodDeferredCapable()
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
height: 18
|
||||
fontSize: 16
|
||||
leftPadding: 0
|
||||
text: "Enabled"
|
||||
checked: Render.renderMethod === 0
|
||||
onClicked: {
|
||||
Render.renderMethod = 0; // "DEFERRED"
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: renderingEffectCheckboxes
|
||||
Layout.preferredWidth: parent.width
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 24
|
||||
anchors.topMargin: 8
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Layout.topMargin
|
||||
enabled: performanceCustom.checked && renderingEffectsEnabled.checked
|
||||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: renderingEffectShadows
|
||||
checked: Render.shadowsEnabled
|
||||
boxSize: 16
|
||||
text: "Shadows"
|
||||
spacing: -1
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
onCheckedChanged: {
|
||||
Render.shadowsEnabled = renderingEffectShadows.checked;
|
||||
}
|
||||
}
|
||||
HifiControlsUit.CheckBox {
|
||||
id: renderingEffectHaze
|
||||
checked: Render.hazeEnabled
|
||||
boxSize: 16
|
||||
text: "Haze"
|
||||
spacing: -1
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: parent.left
|
||||
anchors.top: renderingEffectShadows.bottom
|
||||
onCheckedChanged: {
|
||||
Render.hazeEnabled = renderingEffectHaze.checked;
|
||||
}
|
||||
}
|
||||
HifiControlsUit.CheckBox {
|
||||
id: renderingEffectBloom
|
||||
checked: Render.bloomEnabled
|
||||
boxSize: 16
|
||||
text: "Bloom"
|
||||
spacing: -1
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: parent.left
|
||||
anchors.top: renderingEffectHaze.bottom
|
||||
onCheckedChanged: {
|
||||
Render.bloomEnabled = renderingEffectBloom.checked;
|
||||
}
|
||||
}
|
||||
HifiControlsUit.CheckBox {
|
||||
id: renderingEffectAO
|
||||
checked: Render.ambientOcclusionEnabled
|
||||
boxSize: 16
|
||||
text: "AO"
|
||||
spacing: -1
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: parent.left
|
||||
anchors.top: renderingEffectBloom.bottom
|
||||
onCheckedChanged: {
|
||||
Render.ambientOcclusionEnabled = renderingEffectAO.checked;
|
||||
}
|
||||
}
|
||||
HifiControlsUit.CheckBox {
|
||||
id: renderingEffectLocalLights
|
||||
enabled: false
|
||||
//checked: Render.localLightsEnabled
|
||||
checked: renderingEffectsEnabled.checked
|
||||
boxSize: 16
|
||||
text: "Local lights"
|
||||
spacing: -1
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: parent.left
|
||||
anchors.top: renderingEffectAO.bottom
|
||||
//onCheckedChanged: {
|
||||
// Render.localLightsEnabled = renderingEffectLocalLightsEnabled.checked;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
Layout.topMargin: 10
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: refreshRateHeader
|
||||
text: "Refresh Rate"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: refreshRateModel
|
||||
|
||||
ListElement {
|
||||
text: "Economical"
|
||||
refreshRatePreset: 0 // RefreshRateProfile::ECO
|
||||
}
|
||||
ListElement {
|
||||
text: "Interactive"
|
||||
refreshRatePreset: 1 // RefreshRateProfile::INTERACTIVE
|
||||
}
|
||||
ListElement {
|
||||
text: "Real-Time"
|
||||
refreshRatePreset: 2 // RefreshRateProfile::REALTIME
|
||||
}
|
||||
ListElement {
|
||||
text: "Custom"
|
||||
refreshRatePreset: 3 // RefreshRateProfile::CUSTOM
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: refreshRateDropdown
|
||||
enabled: performanceCustom.checked
|
||||
anchors.left: refreshRateHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
width: 280
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: refreshRateModel
|
||||
currentIndex: -1
|
||||
|
||||
function refreshRefreshRateDropdownDisplay() {
|
||||
refreshRateDropdown.currentIndex = Performance.getRefreshRateProfile();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
refreshRateDropdown.refreshRefreshRateDropdownDisplay();
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
Performance.setRefreshRateProfile(model.get(currentIndex).refreshRatePreset);
|
||||
refreshRateDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
Layout.topMargin: 32
|
||||
visible: refreshRateDropdown.currentIndex == 3
|
||||
|
||||
RowLayout {
|
||||
Layout.margins: 8
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
id: refreshRateCustomFocusActive
|
||||
decimals: 0
|
||||
width: 160
|
||||
height: 32
|
||||
suffix: " FPS"
|
||||
label: "Focus Active"
|
||||
realFrom: 1
|
||||
realTo: 1000
|
||||
realStepSize: 15
|
||||
realValue: 60
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
property var loaded: false
|
||||
|
||||
Component.onCompleted: {
|
||||
realValue = Performance.getCustomRefreshRate(0)
|
||||
loaded = true
|
||||
}
|
||||
|
||||
onRealValueChanged: {
|
||||
if (loaded) {
|
||||
Performance.setCustomRefreshRate(0, realValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
id: refreshRateCustomFocusInactive
|
||||
decimals: 0
|
||||
width: 160
|
||||
height: 32
|
||||
suffix: " FPS"
|
||||
label: "Focus Inactive"
|
||||
realFrom: 1
|
||||
realTo: 1000
|
||||
realStepSize: 15
|
||||
realValue: 60
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
property var loaded: false
|
||||
|
||||
Component.onCompleted: {
|
||||
realValue = Performance.getCustomRefreshRate(1)
|
||||
loaded = true
|
||||
}
|
||||
|
||||
onRealValueChanged: {
|
||||
if (loaded) {
|
||||
Performance.setCustomRefreshRate(1, realValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.margins: 8
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
id: refreshRateCustomUnfocus
|
||||
decimals: 0
|
||||
width: 160
|
||||
height: 32
|
||||
suffix: " FPS"
|
||||
label: "Unfocus"
|
||||
realFrom: 1
|
||||
realTo: 1000
|
||||
realStepSize: 15
|
||||
realValue: 60
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
property var loaded: false
|
||||
|
||||
Component.onCompleted: {
|
||||
realValue = Performance.getCustomRefreshRate(2)
|
||||
loaded = true
|
||||
}
|
||||
|
||||
onRealValueChanged: {
|
||||
if (loaded) {
|
||||
Performance.setCustomRefreshRate(2, realValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
id: refreshRateCustomMinimized
|
||||
decimals: 0
|
||||
width: 160
|
||||
height: 32
|
||||
suffix: " FPS"
|
||||
label: "Minimized"
|
||||
realFrom: 1
|
||||
realTo: 1000
|
||||
realStepSize: 1
|
||||
realValue: 60
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
property var loaded: false
|
||||
|
||||
Component.onCompleted: {
|
||||
realValue = Performance.getCustomRefreshRate(3)
|
||||
loaded = true
|
||||
}
|
||||
|
||||
onRealValueChanged: {
|
||||
if (loaded) {
|
||||
Performance.setCustomRefreshRate(3, realValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.margins: 8
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
id: refreshRateCustomStartup
|
||||
decimals: 0
|
||||
width: 160
|
||||
height: 32
|
||||
suffix: " FPS"
|
||||
label: "Startup"
|
||||
realFrom: 1
|
||||
realTo: 1000
|
||||
realStepSize: 15
|
||||
realValue: 60
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
property var loaded: false
|
||||
|
||||
Component.onCompleted: {
|
||||
realValue = Performance.getCustomRefreshRate(4)
|
||||
loaded = true
|
||||
}
|
||||
|
||||
onRealValueChanged: {
|
||||
if (loaded) {
|
||||
Performance.setCustomRefreshRate(4, realValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.SpinBox {
|
||||
id: refreshRateCustomShutdown
|
||||
decimals: 0
|
||||
width: 160
|
||||
height: 32
|
||||
suffix: " FPS"
|
||||
label: "Shutdown"
|
||||
realFrom: 1
|
||||
realTo: 1000
|
||||
realStepSize: 15
|
||||
realValue: 60
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
property var loaded: false
|
||||
|
||||
Component.onCompleted: {
|
||||
realValue = Performance.getCustomRefreshRate(5)
|
||||
loaded = true
|
||||
}
|
||||
|
||||
onRealValueChanged: {
|
||||
if (loaded) {
|
||||
Performance.setCustomRefreshRate(5, realValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
Layout.topMargin: 16
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: resolutionHeader
|
||||
text: "Resolution Scale (" + Number.parseFloat(Render.viewportResolutionScale).toPrecision(3) + ")"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: resolutionScaleSlider
|
||||
enabled: performanceCustom.checked
|
||||
anchors.left: resolutionHeader.right
|
||||
anchors.leftMargin: 57
|
||||
anchors.top: parent.top
|
||||
width: 150
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
minimumValue: 0.25
|
||||
maximumValue: 2.0
|
||||
stepSize: 0.05
|
||||
value: Render.viewportResolutionScale
|
||||
live: true
|
||||
|
||||
function updateResolutionScale(sliderValue) {
|
||||
if (Render.viewportResolutionScale !== sliderValue) {
|
||||
Render.viewportResolutionScale = sliderValue;
|
||||
}
|
||||
}
|
||||
|
||||
onValueChanged: {
|
||||
updateResolutionScale(value);
|
||||
}
|
||||
onPressedChanged: {
|
||||
if (!pressed) {
|
||||
updateResolutionScale(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
Layout.topMargin: 16
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: fieldOfViewHeader
|
||||
text: "Vertical FOV (" + Number(Math.round(Render.verticalFieldOfView)) + ")"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
HifiControlsUit.Slider {
|
||||
id: fieldOfViewSlider
|
||||
enabled: true
|
||||
anchors.left: fieldOfViewHeader.right
|
||||
anchors.leftMargin: 57
|
||||
anchors.top: parent.top
|
||||
width: 150
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
minimumValue: 20
|
||||
maximumValue: 130
|
||||
stepSize: 0.05
|
||||
value: Render.verticalFieldOfView
|
||||
live: true
|
||||
|
||||
function updateFieldOfView(sliderValue) {
|
||||
if (Render.verticalFieldOfView !== sliderValue) {
|
||||
Render.verticalFieldOfView = sliderValue;
|
||||
}
|
||||
}
|
||||
|
||||
onValueChanged: {
|
||||
updateFieldOfView(value);
|
||||
}
|
||||
onPressedChanged: {
|
||||
if (!pressed) {
|
||||
updateFieldOfView(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
Layout.topMargin: 16
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: enableCameraClippingHeader
|
||||
text: "3rd Person Camera Clipping"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 200
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: enableCameraClipping
|
||||
checked: Render.cameraClippingEnabled
|
||||
boxSize: 16
|
||||
spacing: -1
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: enableCameraClippingHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
onCheckedChanged: {
|
||||
Render.cameraClippingEnabled = enableCameraClipping.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 20
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: antialiasingHeader
|
||||
text: "Anti-aliasing"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: antialiasingModel
|
||||
|
||||
// Maintain same order as "AntialiasingSetupConfig::Mode".
|
||||
ListElement {
|
||||
text: "None"
|
||||
}
|
||||
ListElement {
|
||||
text: "TAA"
|
||||
}
|
||||
ListElement {
|
||||
text: "FXAA"
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: antialiasingDropdown
|
||||
anchors.left: antialiasingHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
width: 280
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: antialiasingModel
|
||||
currentIndex: -1
|
||||
|
||||
function refreshAntialiasingDropdown() {
|
||||
antialiasingDropdown.currentIndex = Render.antialiasingMode;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
antialiasingDropdown.refreshAntialiasingDropdown();
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
Render.antialiasingMode = currentIndex;
|
||||
antialiasingDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 20
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: fullScreenDisplayHeader
|
||||
text: "Full screen display"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 130
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: fullScreenDisplayModel
|
||||
|
||||
ListElement {
|
||||
text: "Screen 1"
|
||||
}
|
||||
|
||||
function refreshScreens() {
|
||||
fullScreenDisplayModel.clear();
|
||||
Render.getScreens().forEach(function(screen) {
|
||||
fullScreenDisplayModel.append({"text" : screen});
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
fullScreenDisplayModel.refreshScreens();
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.ComboBox {
|
||||
id: fullScreenDisplayDropdown
|
||||
anchors.left: fullScreenDisplayHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
width: 280
|
||||
height: parent.height
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
model: fullScreenDisplayModel
|
||||
currentIndex: 0
|
||||
|
||||
function refreshFullScreenDisplayDropdown() {
|
||||
var screens = Render.getScreens();
|
||||
var selected = Render.getFullScreenScreen();
|
||||
|
||||
for(let idx = 0; idx < screens.length; idx++) {
|
||||
if (screens[idx] == selected) {
|
||||
fullScreenDisplayDropdown.currentIndex = idx;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Selected full screen screen", selected, "not found, falling back to primary screen");
|
||||
console.log("List of screens is:", screens);
|
||||
fullScreenDisplayDropdown.currentIndex = 0;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
model.refreshScreens();
|
||||
fullScreenDisplayDropdown.refreshFullScreenDisplayDropdown();
|
||||
fullScreenDisplayDropdown.displayText = model.get(currentIndex).text;
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (currentIndex >= 0) {
|
||||
// Somehow, we end up going through here twice on every change of the combo box.
|
||||
// The first one is with the new selected index, and the second one is with the
|
||||
// index at -1.
|
||||
//
|
||||
// The first one comes from a sensible stack of:
|
||||
// onCurrentIndexChanged (qrc:/qml/hifi/dialogs/graphics/GraphicsSettings.qml:559)
|
||||
// refreshScreens (qrc:/qml/hifi/dialogs/graphics/GraphicsSettings.qml:514)
|
||||
// onCompleted (qrc:/qml/hifi/dialogs/graphics/GraphicsSettings.qml:553)
|
||||
// load (qrc:/qml/hifi/tablet/WindowRoot.qml:170)
|
||||
// loadSource (qrc:/qml/hifi/tablet/WindowRoot.qml:63)
|
||||
//
|
||||
// The second seems to be called out of nowhere. This likely indicates some sort of bug.
|
||||
// Might be related to Wayland?
|
||||
|
||||
Render.setFullScreenScreen(model.get(currentIndex).text);
|
||||
fullScreenDisplayDropdown.displayText = model.get(currentIndex).text;
|
||||
} else {
|
||||
console.log("Called with currentIndex =", currentIndex);
|
||||
console.trace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 20
|
||||
Layout.preferredWidth: parent.width
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: parent.width
|
||||
Layout.preferredHeight: 35
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: proceduralMaterialsHeader
|
||||
text: "Procedural Materials"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
width: 150
|
||||
height: parent.height
|
||||
size: 16
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: renderingEffectProceduralMaterials
|
||||
checked: Render.proceduralMaterialsEnabled
|
||||
boxSize: 16
|
||||
spacing: -1
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
anchors.left: proceduralMaterialsHeader.right
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
onCheckedChanged: {
|
||||
Render.proceduralMaterialsEnabled = renderingEffectProceduralMaterials.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function refreshAllDropdowns() {
|
||||
worldDetailDropdown.refreshWorldDetailDropdown();
|
||||
refreshRateDropdown.refreshRefreshRateDropdownDisplay();
|
||||
antialiasingDropdown.refreshAntialiasingDropdown();
|
||||
}
|
||||
}
|
|
@ -286,18 +286,6 @@ Menu::Menu() {
|
|||
}
|
||||
});
|
||||
|
||||
// Settings > Graphics...
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Graphics...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
tablet->pushOntoStack("hifi/dialogs/graphics/GraphicsSettings.qml");
|
||||
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->toggleShouldShowTablet();
|
||||
}
|
||||
});
|
||||
|
||||
// Settings > Security...
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Security...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
|
|
|
@ -24,7 +24,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
"system/snapshot.js",
|
||||
"system/pal.js", // "system/mod.js", // older UX, if you prefer
|
||||
"system/avatarapp.js",
|
||||
"system/graphicsSettings.js",
|
||||
"system/settings/settings.js",
|
||||
"system/makeUserConnection.js",
|
||||
"system/notifications.js",
|
||||
"system/create/edit.js",
|
||||
|
|
|
@ -1,102 +0,0 @@
|
|||
//
|
||||
// graphicsSettings.js
|
||||
//
|
||||
// Created by Kalila L. on August 5th, 2020
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
// Copyright 2024 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
var channelComm = "Overte-ShowGraphicsIconChanged";
|
||||
var appStatus = false;
|
||||
var GRAPHICS_HIDE_AND_SHOW_SETTING_KEY = "showGraphicsIcon";
|
||||
var GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE = true;
|
||||
|
||||
var AppUi = Script.require('appUi');
|
||||
|
||||
// cellphone-cog MDI
|
||||
// var customIcon = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24"><path fill="white" d="M9.82,12.5C9.84,12.33 9.86,12.17 9.86,12C9.86,11.83 9.84,11.67 9.82,11.5L10.9,10.69C11,10.62 11,10.5 10.96,10.37L9.93,8.64C9.87,8.53 9.73,8.5 9.62,8.53L8.34,9.03C8.07,8.83 7.78,8.67 7.47,8.54L7.27,7.21C7.27,7.09 7.16,7 7.03,7H5C4.85,7 4.74,7.09 4.72,7.21L4.5,8.53C4.21,8.65 3.92,8.83 3.65,9L2.37,8.5C2.25,8.47 2.12,8.5 2.06,8.63L1.03,10.36C0.97,10.5 1,10.61 1.1,10.69L2.18,11.5C2.16,11.67 2.15,11.84 2.15,12C2.15,12.17 2.17,12.33 2.19,12.5L1.1,13.32C1,13.39 1,13.53 1.04,13.64L2.07,15.37C2.13,15.5 2.27,15.5 2.38,15.5L3.66,15C3.93,15.18 4.22,15.34 4.53,15.47L4.73,16.79C4.74,16.91 4.85,17 5,17H7.04C7.17,17 7.28,16.91 7.29,16.79L7.5,15.47C7.8,15.35 8.09,15.17 8.36,15L9.64,15.5C9.76,15.53 9.89,15.5 9.95,15.37L11,13.64C11.04,13.53 11,13.4 10.92,13.32L9.82,12.5M6,13.75C5,13.75 4.2,12.97 4.2,12C4.2,11.03 5,10.25 6,10.25C7,10.25 7.8,11.03 7.8,12C7.8,12.97 7,13.75 6,13.75M17,1H7A2,2 0 0,0 5,3V6H7V4H17V20H7V18H5V21A2,2 0 0,0 7,23H17A2,2 0 0,0 19,21V3A2,2 0 0,0 17,1Z" /></svg>'
|
||||
|
||||
// application-cog MDI
|
||||
var customIcon = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24"><path fill="white" d="M21.7 18.6V17.6L22.8 16.8C22.9 16.7 23 16.6 22.9 16.5L21.9 14.8C21.9 14.7 21.7 14.7 21.6 14.7L20.4 15.2C20.1 15 19.8 14.8 19.5 14.7L19.3 13.4C19.3 13.3 19.2 13.2 19.1 13.2H17.1C16.9 13.2 16.8 13.3 16.8 13.4L16.6 14.7C16.3 14.9 16.1 15 15.8 15.2L14.6 14.7C14.5 14.7 14.4 14.7 14.3 14.8L13.3 16.5C13.3 16.6 13.3 16.7 13.4 16.8L14.5 17.6V18.6L13.4 19.4C13.3 19.5 13.2 19.6 13.3 19.7L14.3 21.4C14.4 21.5 14.5 21.5 14.6 21.5L15.8 21C16 21.2 16.3 21.4 16.6 21.5L16.8 22.8C16.9 22.9 17 23 17.1 23H19.1C19.2 23 19.3 22.9 19.3 22.8L19.5 21.5C19.8 21.3 20 21.2 20.3 21L21.5 21.4C21.6 21.4 21.7 21.4 21.8 21.3L22.8 19.6C22.9 19.5 22.9 19.4 22.8 19.4L21.7 18.6M18 19.5C17.2 19.5 16.5 18.8 16.5 18S17.2 16.5 18 16.5 19.5 17.2 19.5 18 18.8 19.5 18 19.5M11.29 20H5C3.89 20 3 19.1 3 18V6C3 4.89 3.9 4 5 4H19C20.11 4 21 4.9 21 6V11.68C20.38 11.39 19.71 11.18 19 11.08V8H5V18H11C11 18.7 11.11 19.37 11.29 20Z" /></svg>'
|
||||
var lqIcon = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24"><path fill="white" d="M14.5,13.5H16.5V10.5H14.5M18,14C18,14.6 17.6,15 17,15H16.25V16.5H14.75V15H14C13.4,15 13,14.6 13,14V10C13,9.4 13.4,9 14,9H17C17.6,9 18,9.4 18,10M19,4H5A2,2 0 0,0 3,6V18A2,2 0 0,0 5,20H19A2,2 0 0,0 21,18V6A2,2 0 0,0 19,4M11,13.5V15H6V9H7.5V13.5H11Z" /></svg>';
|
||||
var mqIcon = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24"><path fill="white" d="M21,6V18A2,2 0 0,1 19,20H5A2,2 0 0,1 3,18V6A2,2 0 0,1 5,4H19A2,2 0 0,1 21,6M12,10C12,9.5 11.5,9 11,9H6.5C6,9 5.5,9.5 5.5,10V15H7V10.5H8V14H9.5V10.5H10.5V15H12V10M14.5,9A1,1 0 0,0 13.5,10V14A1,1 0 0,0 14.5,15H15.5V16.5H16.75V15H17.5A1,1 0 0,0 18.5,14V10A1,1 0 0,0 17.5,9H14.5M15,10.5H17V13.5H15V10.5Z" /></svg>';
|
||||
var hqIcon = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24"><path fill="white" d="M14.5,13.5H16.5V10.5H14.5M18,14A1,1 0 0,1 17,15H16.25V16.5H14.75V15H14A1,1 0 0,1 13,14V10A1,1 0 0,1 14,9H17A1,1 0 0,1 18,10M11,15H9.5V13H7.5V15H6V9H7.5V11.5H9.5V9H11M19,4H5C3.89,4 3,4.89 3,6V18A2,2 0 0,0 5,20H19A2,2 0 0,0 21,18V6C21,4.89 20.1,4 19,4Z" /></svg>';
|
||||
|
||||
var BUTTON_NAME = "GRAPHICS";
|
||||
var GRAPHICS_QML_SOURCE = "hifi/dialogs/graphics/GraphicsSettings.qml";
|
||||
var ui;
|
||||
|
||||
function getIcon() {
|
||||
// TODO: Implement only once AppUi can be told to constantly retrieve / reset icons...
|
||||
// var performanceProfile = Performance.getPerformancePreset();
|
||||
//
|
||||
// switch (performanceProfile) {
|
||||
// case 0:
|
||||
// return customIcon;
|
||||
// break;
|
||||
// case 1:
|
||||
// return lqIcon;
|
||||
// break;
|
||||
// case 2:
|
||||
// return mqIcon;
|
||||
// break;
|
||||
// case 3:
|
||||
// return hqIcon;
|
||||
// break;
|
||||
// default:
|
||||
// return customIcon;
|
||||
// }
|
||||
return customIcon;
|
||||
}
|
||||
|
||||
function startup() {
|
||||
if (!appStatus) {
|
||||
ui = new AppUi({
|
||||
buttonName: BUTTON_NAME,
|
||||
sortOrder: 8,
|
||||
normalButton: getIcon(),
|
||||
activeButton: getIcon().replace('white', 'black'),
|
||||
home: GRAPHICS_QML_SOURCE
|
||||
});
|
||||
}
|
||||
appStatus = true;
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
if (appStatus) {
|
||||
ui.onScriptEnding();
|
||||
appStatus = false;
|
||||
}
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Messages.messageReceived.disconnect(onMessageReceived);
|
||||
Messages.unsubscribe(channelComm);
|
||||
}
|
||||
|
||||
function onMessageReceived(channel, message, sender, localOnly) {
|
||||
if (channel === channelComm && localOnly) {
|
||||
if (Settings.getValue(GRAPHICS_HIDE_AND_SHOW_SETTING_KEY, GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE)) {
|
||||
startup();
|
||||
} else {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Run the functions.
|
||||
//
|
||||
if (Settings.getValue(GRAPHICS_HIDE_AND_SHOW_SETTING_KEY, GRAPHICS_HIDE_AND_SHOW_DEFAULT_VALUE)) {
|
||||
startup();
|
||||
}
|
||||
Messages.subscribe(channelComm);
|
||||
Messages.messageReceived.connect(onMessageReceived);
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
116
scripts/system/settings/README.md
Normal file
|
@ -0,0 +1,116 @@
|
|||
# Settings
|
||||
This application allows users to adjust multiple aspects of the Overte application.
|
||||
|
||||
## Developing
|
||||
|
||||
### QML Widgets
|
||||
This application provides several QML widgets to make adding additional settings easy.
|
||||
The important settings related widgets are as follows:
|
||||
|
||||
| Name | Description |
|
||||
|---------------------|------------------------------------------------------------------------|
|
||||
| SettingBoolean.qml | An enable/disable toggle for a provided setting |
|
||||
| SettingComboBox.qml | A drop down element which provides a list of options |
|
||||
| SettingNumber.qml | An input which only allows numerical data entry |
|
||||
| SettingSlider.qml | An input which only allows numerical data entry, presented as a slider |
|
||||
|
||||
#### Examples
|
||||
|
||||
SettingBoolean.qml:
|
||||
```qml
|
||||
SettingBoolean {
|
||||
// Provide the label for the setting (String).
|
||||
settingText: "Rendering effects";
|
||||
|
||||
// Pass a function that is executed and the resulting value is set to the internal variable "settingEnabled"
|
||||
// This function is executed when the component is loaded, setting the initial state of the boolean.
|
||||
// When setting a graphics preset, all SettingBoolean elements have their "update()" function executed.
|
||||
// The "update()" function executes the function provided here as the "settingEnabledCondition".
|
||||
settingEnabledCondition: function () { return Render.renderMethod === 0; }
|
||||
|
||||
// When the value is changed, execute...
|
||||
onSettingEnabledChanged: {
|
||||
// Adjust the application setting to the current value of this boolean.
|
||||
Render.renderMethod = settingEnabled ? 0 : 1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
SettingComboBox.qml:
|
||||
```qml
|
||||
SettingComboBox {
|
||||
// Provide the label for the setting (String).
|
||||
settingText: "Refresh rate";
|
||||
|
||||
// Options for the setting (Array of strings)
|
||||
options: ["Economical", "Interactive", "Real-Time", "Custom"];
|
||||
|
||||
// Set the index of the combobox based on the current setting (int).
|
||||
optionIndex: Performance.getRefreshRateProfile();
|
||||
|
||||
// When the value is changed, execute...
|
||||
onValueChanged: {
|
||||
// Adjust the application setting to the current value of the combobox.
|
||||
// Note: the "index" variable provides the index of the provided options which is selected.
|
||||
Performance.setRefreshRateProfile(index);
|
||||
|
||||
// If the index is 3 (Custom), show advanced settings, otherwise hide advanced settings.
|
||||
customFPSVaulesContainer.visible = index == 3;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
SettingNumber.qml:
|
||||
```qml
|
||||
SettingNumber {
|
||||
// Provide the label for the setting (String).
|
||||
settingText: "Focus Active";
|
||||
|
||||
// Set the minimum value allowed for this input (real).
|
||||
minValue: 5;
|
||||
|
||||
// Set the maximum value allowed (real).
|
||||
maxValue: 9999;
|
||||
|
||||
// Extra text to add at the far right of the element.
|
||||
suffixText: "fps";
|
||||
|
||||
// Set the initial value of the number based on the current setting (var).
|
||||
settingValue: Performance.getCustomRefreshRate(0);
|
||||
|
||||
// When the value is changed, execute...
|
||||
onValueChanged: {
|
||||
// Adjust the application setting to the current value of this number.
|
||||
// Note: the "value" variable provides the current value of this element.
|
||||
Performance.setCustomRefreshRate(0, value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
SettingSlider.qml:
|
||||
```qml
|
||||
SettingSlider {
|
||||
// Provide the label for the setting (String).
|
||||
settingText: "Resolution scale";
|
||||
|
||||
// Set the step size for the slider (real).
|
||||
sliderStepSize: 0.1;
|
||||
|
||||
// Set the minimum value allowed by the slider (real).
|
||||
minValue: 0.1;
|
||||
|
||||
// Set the maximum value allowed by the slider (real).
|
||||
maxValue: 2;
|
||||
|
||||
// Set the initial value based on the current setting (var).
|
||||
settingValue: Render.viewportResolutionScale.toFixed(1)
|
||||
|
||||
// When the value is changed, execute...
|
||||
onSliderValueChanged: {
|
||||
// Adjust the application setting to the current value of this slider.
|
||||
// Note: the "value" variable provides the current value of this element.
|
||||
Render.viewportResolutionScale = value.toFixed(1)
|
||||
}
|
||||
}
|
||||
```
|
71
scripts/system/settings/Settings.qml
Normal file
|
@ -0,0 +1,71 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.3
|
||||
import "./qml"
|
||||
import "./qml/pages"
|
||||
|
||||
Rectangle {
|
||||
signal sendToScript(var message);
|
||||
color: Qt.rgba(0.1,0.1,0.1,1);
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
anchors.centerIn: parent;
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
property var pages: [
|
||||
{name: "General", icon: "../img/overte.svg", targetPage: "hifi/tablet/TabletGeneralPreferences.qml" },
|
||||
{name: "Graphics", icon: "../img/computer.svg", targetPage: "" },
|
||||
{name: "Audio", icon: "../img/volume.svg", targetPage: "hifi/audio/Audio.qml" },
|
||||
{name: "Controls", icon: "../img/dpad.svg", targetPage: "hifi/tablet/ControllerSettings.qml" },
|
||||
{name: "Security", icon: "../img/badge.svg", targetPage: "hifi/dialogs/security/Security.qml" },
|
||||
{name: "QML Allowlist", icon: "../img/lock.svg", targetPage: "hifi/dialogs/security/EntityScriptQMLAllowlist.qml" },
|
||||
{name: "Script Security", icon: "../img/shield.svg", targetPage: "hifi/dialogs/security/ScriptSecurity.qml" },
|
||||
];
|
||||
property string currentPage: "Settings"
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
id: root
|
||||
|
||||
// Navigation Header
|
||||
HeaderElement {
|
||||
id: header
|
||||
}
|
||||
|
||||
// Home page
|
||||
SettingCenterContainer {
|
||||
id: homePage
|
||||
visible: currentPage == "Settings"
|
||||
Layout.fillHeight: true
|
||||
|
||||
Repeater {
|
||||
model: pages.length;
|
||||
delegate: SettingSubviewListElement {
|
||||
property string pageName: pages[index].name;
|
||||
property string pageIcon: pages[index].icon;
|
||||
property string targetPage: pages[index].targetPage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Graphics
|
||||
GraphicsSettings {}
|
||||
|
||||
// Templates
|
||||
}
|
||||
|
||||
// Messages from script
|
||||
function fromScript(message) {
|
||||
switch (message.type){
|
||||
case "loadPage":
|
||||
currentPage = message.page;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Send message to script
|
||||
function toScript(packet){
|
||||
sendToScript(packet)
|
||||
}
|
||||
}
|
BIN
scripts/system/settings/img/back_arrow.png
Normal file
After Width: | Height: | Size: 501 B |
39
scripts/system/settings/img/back_arrow.svg
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="24px"
|
||||
viewBox="0 -960 960 960"
|
||||
width="24px"
|
||||
fill="#5f6368"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="back_arrow.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="48.541667"
|
||||
inkscape:cx="11.9897"
|
||||
inkscape:cy="12"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1363"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m313-440 224 224-57 56-320-320 320-320 57 56-224 224h487v80H313Z"
|
||||
id="path1"
|
||||
style="fill:#ffffff" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
38
scripts/system/settings/img/badge.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="20"
|
||||
viewBox="0 -960 800 800"
|
||||
width="20"
|
||||
fill="#ffffff"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="badge.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="50.375"
|
||||
inkscape:cx="9.9950372"
|
||||
inkscape:cy="9.9950372"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M 80,-160 Q 47,-160 23.5,-183.5 0,-207 0,-240 V -680 Q 0,-713 23.5,-736.5 47,-760 80,-760 h 200 v -120 q 0,-33 23.5,-56.5 Q 327,-960 360,-960 h 80 q 33,0 56.5,23.5 23.5,23.5 23.5,56.5 v 120 h 200 q 33,0 56.5,23.5 23.5,23.5 23.5,56.5 v 440 q 0,33 -23.5,56.5 Q 753,-160 720,-160 Z m 0,-80 H 720 V -680 H 520 q 0,33 -23.5,56.5 Q 473,-600 440,-600 h -80 q -33,0 -56.5,-23.5 Q 280,-647 280,-680 H 80 Z m 80,-80 h 240 v -18 q 0,-17 -9.5,-31.5 Q 381,-384 364,-392 344,-401 323.5,-405.5 303,-410 280,-410 q -23,0 -43.5,4.5 -20.5,4.5 -40.5,13.5 -17,8 -26.5,22.5 -9.5,14.5 -9.5,31.5 z m 320,-60 h 160 v -60 H 480 Z m -200,-60 q 25,0 42.5,-17.5 Q 340,-475 340,-500 340,-525 322.5,-542.5 305,-560 280,-560 q -25,0 -42.5,17.5 -17.5,17.5 -17.5,42.5 0,25 17.5,42.5 17.5,17.5 42.5,17.5 z m 200,-60 h 160 v -60 H 480 Z M 360,-680 h 80 v -200 h -80 z m 40,220 z"
|
||||
id="path1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
39
scripts/system/settings/img/computer.svg
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="18"
|
||||
viewBox="0 -960 880 720"
|
||||
width="22"
|
||||
fill="#5f6368"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="computer.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="50.166667"
|
||||
inkscape:cx="11.013289"
|
||||
inkscape:cy="8.9900332"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1407"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 0,-240 v -80 h 880 v 80 z M 120,-360 Q 87,-360 63.5,-383.5 40,-407 40,-440 v -440 q 0,-33 23.5,-56.5 Q 87,-960 120,-960 h 640 q 33,0 56.5,23.5 23.5,23.5 23.5,56.5 v 440 q 0,33 -23.5,56.5 Q 793,-360 760,-360 Z m 0,-80 H 760 V -880 H 120 Z m 0,0 v -440 z"
|
||||
id="path1"
|
||||
style="fill:#ffffff" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
38
scripts/system/settings/img/dpad.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="20"
|
||||
viewBox="0 -960 800 800"
|
||||
width="20"
|
||||
fill="#ffffff"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="dpad.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="50.375"
|
||||
inkscape:cx="9.9950372"
|
||||
inkscape:cy="9.9950372"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 400,-734 z m 174,174 z m -348,0 z m 174,174 z m 0,-234 -120,-120 v -220 h 240 v 220 z m 180,180 -120,-120 120,-120 h 220 v 240 z m -580,0 v -240 h 220 l 120,120 -120,120 z m 280,280 v -220 l 120,-120 120,120 v 220 z m 120,-574 40,-40 v -106 h -80 v 106 z M 80,-520 h 106 l 40,-40 -40,-40 H 80 Z m 280,280 h 80 v -106 l -40,-40 -40,40 z m 254,-280 h 106 v -80 H 614 l -40,40 z"
|
||||
id="path1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
BIN
scripts/system/settings/img/icon_black.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
scripts/system/settings/img/icon_white.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
38
scripts/system/settings/img/lock.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="21"
|
||||
viewBox="0 -960 640 840"
|
||||
width="16"
|
||||
fill="#ffffff"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="lock.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="48.541667"
|
||||
inkscape:cx="8.0034335"
|
||||
inkscape:cy="10.990558"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M 80,-120 Q 47,-120 23.5,-143.5 0,-167 0,-200 V -600 Q 0,-633 23.5,-656.5 47,-680 80,-680 h 40 v -80 q 0,-83 58.5,-141.5 Q 237,-960 320,-960 q 83,0 141.5,58.5 Q 520,-843 520,-760 v 80 h 40 q 33,0 56.5,23.5 23.5,23.5 23.5,56.5 v 400 q 0,33 -23.5,56.5 Q 593,-120 560,-120 Z m 0,-80 H 560 V -600 H 80 Z m 240,-120 q 33,0 56.5,-23.5 Q 400,-367 400,-400 400,-433 376.5,-456.5 353,-480 320,-480 q -33,0 -56.5,23.5 -23.5,23.5 -23.5,56.5 0,33 23.5,56.5 Q 287,-320 320,-320 Z M 200,-680 h 240 v -80 q 0,-50 -35,-85 -35,-35 -85,-35 -50,0 -85,35 -35,35 -35,85 z M 80,-200 v -400 z"
|
||||
id="path1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
71
scripts/system/settings/img/overte.svg
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="11.276092mm"
|
||||
height="11.15854mm"
|
||||
viewBox="0 0 11.276092 11.15854"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="overte.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<title
|
||||
id="title715">LOGO_Overte_Org_Black</title>
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#d1d1d1"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.2057243"
|
||||
inkscape:cx="157.99632"
|
||||
inkscape:cy="-143.89691"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1" />
|
||||
<defs
|
||||
id="defs2" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="pastille"
|
||||
style="display:inline"
|
||||
transform="translate(-66.674462,-49.002321)" />
|
||||
<g
|
||||
inkscape:label="Letters"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
style="display:inline"
|
||||
transform="translate(-66.674462,-49.002321)">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.0240699"
|
||||
d="m 71.752748,60.147164 c -1.377172,-0.14605 -2.574378,-0.732869 -3.530213,-1.730362 -0.825342,-0.861313 -1.341717,-1.931985 -1.516444,-3.144257 -0.04744,-0.329165 -0.04014,-1.234694 0.01269,-1.573208 0.220327,-1.411764 0.906991,-2.625395 2.001937,-3.538291 0.406864,-0.339217 0.998514,-0.688227 1.513503,-0.892803 0.204169,-0.0811 0.718969,-0.241851 0.774539,-0.241851 0.02985,0 0.03471,0.208002 0.03471,1.487877 v 1.48788 l -0.09026,0.04291 c -0.261261,0.124198 -0.69358,0.506545 -0.926976,0.819823 -0.7253,0.973539 -0.719063,2.366351 0.01495,3.335577 0.675906,0.892517 1.728786,1.300709 2.82169,1.093946 1.110321,-0.210056 2.027379,-1.147031 2.226244,-2.274592 0.04085,-0.23159 0.04094,-0.754422 2.06e-4,-0.986869 -0.07876,-0.449196 -0.279384,-0.901684 -0.549607,-1.239604 -0.23905,-0.298937 -0.685088,-0.667484 -0.963399,-0.796026 L 73.475802,51.95089 73.4751,50.476605 c -4.67e-4,-1.042841 0.007,-1.474284 0.02546,-1.474284 0.05635,0 0.413281,0.100024 0.646028,0.181038 2.077867,0.723258 3.543285,2.558867 3.779523,4.734302 0.03259,0.300057 0.03259,0.917373 0,1.21743 -0.116007,1.068259 -0.594065,2.195254 -1.273315,3.001776 -0.907409,1.077435 -2.114515,1.75767 -3.504262,1.974746 -0.280638,0.04384 -1.116884,0.06513 -1.395838,0.03555 z"
|
||||
id="path339"
|
||||
sodipodi:nodetypes="cssssssscsscsscssccscsssscc" />
|
||||
</g>
|
||||
<metadata
|
||||
id="metadata713">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:title>LOGO_Overte_Org_Black</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
38
scripts/system/settings/img/shield.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="20"
|
||||
viewBox="0 -960 640 800"
|
||||
width="16"
|
||||
fill="#ffffff"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="shield.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="48.541667"
|
||||
inkscape:cx="8.0034335"
|
||||
inkscape:cy="10.001717"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="M 320,-160 Q 181,-195 90.5,-319.5 0,-444 0,-596 v -244 l 320,-120 320,120 v 244 q 0,152 -90.5,276.5 Q 459,-195 320,-160 Z m 0,-84 q 104,-33 172,-132 68,-99 68,-220 v -189 l -240,-90 -240,90 v 189 q 0,121 68,220 68,99 172,132 z m 0,-316 z"
|
||||
id="path1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
38
scripts/system/settings/img/volume.svg
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="17.5"
|
||||
viewBox="0 -960 720 700"
|
||||
width="18"
|
||||
fill="#ffffff"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="volume2.svg"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="50.375"
|
||||
inkscape:cx="9.0024814"
|
||||
inkscape:cy="8.7841191"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<path
|
||||
d="m 440,-260 v -82 q 90,-26 145,-100 55,-74 55,-168 0,-94 -55,-168 -55,-74 -145,-100 v -82 q 124,28 202,125.5 78,97.5 78,224.5 0,127 -78,224.5 Q 564,-288 440,-260 Z M 0,-489 v -240 h 160 l 200,-200 v 640 L 160,-489 Z m 440,40 v -322 q 47,22 73.5,66 26.5,44 26.5,96 0,51 -26.5,94.5 Q 487,-471 440,-449 Z m -160,-286 -86,86 H 80 v 80 h 114 l 86,86 z m -100,126 z"
|
||||
id="path1" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
63
scripts/system/settings/qml/AdvancedOptions.qml
Normal file
|
@ -0,0 +1,63 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.5
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
Item {
|
||||
property var isEnabled: false;
|
||||
height: 0;
|
||||
width: parent.width;
|
||||
id: advancedOptionsRoot;
|
||||
clip: true;
|
||||
|
||||
// Despite my best efforts, a timer is needed here to check to see if we need to expand on start.
|
||||
// After the children are all moved to the advancedOptionsList column, this timer should start and correctly set
|
||||
// the desired state.
|
||||
Timer {
|
||||
id: initExpandTimer;
|
||||
interval: 100;
|
||||
repeat: false;
|
||||
running: false;
|
||||
|
||||
onTriggered: {
|
||||
if (isEnabled) advancedOptionsRoot.height = advancedOptionsList.height;
|
||||
}
|
||||
}
|
||||
|
||||
// Expand Vertically on enabled animation.
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 200;
|
||||
easing.type: Easing.InOutCubic;
|
||||
}
|
||||
}
|
||||
|
||||
onIsEnabledChanged: {
|
||||
if (isEnabled) advancedOptionsRoot.height = advancedOptionsList.height;
|
||||
else advancedOptionsRoot.height = 0;
|
||||
}
|
||||
|
||||
// Content Container.
|
||||
Rectangle {
|
||||
color: "#222222";
|
||||
width: parent.width;
|
||||
height: advancedOptionsList.height;
|
||||
radius: 10;
|
||||
|
||||
// Content List.
|
||||
ColumnLayout {
|
||||
width: parent.width - 10;
|
||||
id: advancedOptionsList;
|
||||
}
|
||||
}
|
||||
|
||||
// Append all children created to this widget to the correct element.
|
||||
Component.onCompleted: {
|
||||
while (advancedOptionsRoot.children.length > 1){
|
||||
advancedOptionsRoot.children[1].parent = advancedOptionsList;
|
||||
|
||||
// On the last child moved, run a timer to check to see if we need to expand
|
||||
initExpandTimer.running = true;
|
||||
}
|
||||
}
|
||||
}
|
44
scripts/system/settings/qml/HeaderElement.qml
Normal file
|
@ -0,0 +1,44 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
Item {
|
||||
height: 60;
|
||||
width: parent.width;
|
||||
id: root;
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent;
|
||||
color: "black";
|
||||
}
|
||||
|
||||
Image {
|
||||
source: "../img/back_arrow.png";
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: 40;
|
||||
width: 40;
|
||||
x: currentPage == "Settings" ? -40 : 10;
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: 200;
|
||||
easing.type: Easing.InOutCubic;
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
onClicked: {
|
||||
currentPage = "Settings";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: currentPage;
|
||||
color: "white";
|
||||
font.pixelSize: 26;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
}
|
||||
}
|
129
scripts/system/settings/qml/SettingBoolean.qml
Normal file
|
@ -0,0 +1,129 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.3
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Item {
|
||||
id: root;
|
||||
property string settingText: "";
|
||||
property bool settingEnabled: false;
|
||||
property var settingEnabledCondition;
|
||||
|
||||
height: 50;
|
||||
width: parent.width;
|
||||
|
||||
Rectangle {
|
||||
id: backgroundElement;
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
color: "transparent";
|
||||
radius: 15;
|
||||
|
||||
RowLayout {
|
||||
width: parent.width - 10;
|
||||
height: parent.height;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
|
||||
|
||||
TextEdit {
|
||||
id: settingTextElem
|
||||
height: parent.height;
|
||||
text: settingText;
|
||||
color: "white";
|
||||
font.pixelSize: 22;
|
||||
selectByMouse: true;
|
||||
readOnly: true;
|
||||
}
|
||||
|
||||
Switch {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight;
|
||||
checked: settingEnabled;
|
||||
implicitHeight: 20;
|
||||
|
||||
indicator: Item {
|
||||
implicitWidth: 70;
|
||||
implicitHeight: parent.implicitHeight;
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: height / 2
|
||||
color: parent.parent.checked ? "#5153bd" : "gray";
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
width: 30
|
||||
height: 30
|
||||
radius: height;
|
||||
color: "white"
|
||||
x: parent.parent.checked ? parent.width - width : 0;
|
||||
y: (parent.implicitHeight - height) / 2
|
||||
|
||||
// Movement animation
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: 100;
|
||||
easing.type: Easing.InOutCubic;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onCheckedChanged: {
|
||||
Tablet.playSound(TabletEnums.ButtonClicked);
|
||||
settingEnabled = checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
propagateComposedEvents: true;
|
||||
|
||||
onPressed: {
|
||||
mouse.accepted = false
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
backgroundElement.color = "#333";
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundElement.color = "transparent";
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 50
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
update();
|
||||
}
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
if (isChangingPreset === false) {
|
||||
// We don't want to update this variable if we are changing to a preset.
|
||||
hasPresetBeenModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
function update(){
|
||||
if (settingEnabledCondition && typeof settingEnabledCondition === "function") {
|
||||
settingEnabled = settingEnabledCondition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
scripts/system/settings/qml/SettingCenterContainer.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
ScrollView {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
y: header.height
|
||||
id: root
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: 0
|
||||
}
|
||||
|
||||
// Append children made using this custom element to the ColumnLayout.
|
||||
Component.onCompleted: {
|
||||
while (root.contentChildren.length > 1){
|
||||
root.contentChildren[2].parent = root.contentChildren[0]
|
||||
}
|
||||
}
|
||||
}
|
196
scripts/system/settings/qml/SettingComboBox.qml
Normal file
|
@ -0,0 +1,196 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.3
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Item {
|
||||
id: root;
|
||||
property string settingText: "";
|
||||
property int optionIndex: 0;
|
||||
property var _optionText: "";
|
||||
readonly property string optionText: _optionText;
|
||||
property var options: [""];
|
||||
|
||||
signal valueChanged(int index);
|
||||
|
||||
height: 50;
|
||||
width: parent.width;
|
||||
|
||||
Rectangle {
|
||||
id: backgroundElement;
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
color: "transparent";
|
||||
radius: 15;
|
||||
|
||||
RowLayout {
|
||||
width: parent.width - 10;
|
||||
height: parent.height;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
Layout.alignment: Qt.AlignTop;
|
||||
|
||||
TextEdit {
|
||||
id: settingTextElem
|
||||
height: parent.height;
|
||||
text: settingText;
|
||||
color: "white";
|
||||
font.pixelSize: 22;
|
||||
selectByMouse: true;
|
||||
readOnly: true;
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: control
|
||||
Layout.alignment: Qt.AlignRight;
|
||||
implicitWidth: 225;
|
||||
implicitHeight: parent.height - 15;
|
||||
model: options;
|
||||
currentIndex: optionIndex;
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
valueChanged(currentIndex);
|
||||
_optionText = options[currentIndex];
|
||||
}
|
||||
|
||||
delegate: ItemDelegate {
|
||||
width: control.width
|
||||
contentItem: Text {
|
||||
text: options[index]
|
||||
color: "white"
|
||||
font: control.font
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
background: Rectangle {
|
||||
color: highlighted ? "gray" : "transparent";
|
||||
radius: 10
|
||||
}
|
||||
highlighted: control.highlightedIndex === index
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
width: parent.width - 20;
|
||||
height: parent.height;
|
||||
|
||||
Item {
|
||||
width: parent.width - 10;
|
||||
height: parent.height;
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent;
|
||||
width: parent.width;
|
||||
text: control.displayText;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
elide: Text.ElideRight;
|
||||
font.pixelSize: 22;
|
||||
color: "white";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
id: comboBoxBackground;
|
||||
color: "#333";
|
||||
radius: 10;
|
||||
width: parent.width;
|
||||
}
|
||||
|
||||
popup: Popup {
|
||||
width: control.width
|
||||
padding: 1
|
||||
|
||||
contentItem: ListView {
|
||||
clip: true
|
||||
implicitHeight: contentHeight
|
||||
model: control.popup.visible ? control.delegateModel : null
|
||||
currentIndex: control.highlightedIndex
|
||||
|
||||
ScrollIndicator.vertical: ScrollIndicator { }
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: Qt.rgba(0,0,0,0.9)
|
||||
radius: 10
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
Tablet.playSound(TabletEnums.ButtonClicked);
|
||||
}
|
||||
}
|
||||
|
||||
indicator: Canvas {
|
||||
id: canvas
|
||||
x: control.width - width - control.rightPadding
|
||||
y: control.topPadding + (control.availableHeight - height) / 2
|
||||
width: 12
|
||||
height: 8
|
||||
contextType: "2d"
|
||||
|
||||
Connections {
|
||||
target: control
|
||||
function onPressedChanged() { canvas.requestPaint(); }
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
context.reset();
|
||||
context.moveTo(0, 0);
|
||||
context.lineTo(width, 0);
|
||||
context.lineTo(width / 2, height);
|
||||
context.closePath();
|
||||
context.fillStyle = "white";
|
||||
context.fill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
propagateComposedEvents: true;
|
||||
|
||||
onPressed: {
|
||||
mouse.accepted = false
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
backgroundElement.color = "#333";
|
||||
comboBoxBackground.color = "#444";
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundElement.color = "transparent";
|
||||
comboBoxBackground.color = "#333";
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 50
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the contents of a combobox.
|
||||
// This is only required if the desired contents needs to be gathered from a javascript function and then set after the fact.
|
||||
// Ideally, this would not be used, but sometimes you gotta do what you gotta do.
|
||||
function setOptions(newOptions) {
|
||||
// Clear the model
|
||||
options = [];
|
||||
|
||||
// Add the new options to the model
|
||||
for (var opt of newOptions){
|
||||
options.push(opt);
|
||||
}
|
||||
|
||||
// Whack it with a hammer
|
||||
control.model = options;
|
||||
}
|
||||
|
||||
function setOptionIndex(index) {
|
||||
control.currentIndex = index;
|
||||
}
|
||||
}
|
187
scripts/system/settings/qml/SettingNumber.qml
Normal file
|
@ -0,0 +1,187 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.5
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
Item {
|
||||
id: root;
|
||||
property string settingText: "";
|
||||
property var settingValue: 0;
|
||||
|
||||
property real minValue: 0;
|
||||
property real maxValue: 9;
|
||||
property string suffixText: "";
|
||||
property real stepSize: 1;
|
||||
property color buttonColor: "#333";
|
||||
|
||||
signal valueChanged(int value);
|
||||
|
||||
height: 50;
|
||||
width: parent.width;
|
||||
|
||||
Rectangle {
|
||||
id: backgroundElement;
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
color: "transparent";
|
||||
radius: 15;
|
||||
|
||||
RowLayout {
|
||||
width: parent.width - 10;
|
||||
height: parent.height;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
Layout.alignment: Qt.AlignTop;
|
||||
|
||||
TextEdit {
|
||||
id: settingTextElem
|
||||
height: parent.height;
|
||||
text: settingText;
|
||||
color: "white";
|
||||
font.pixelSize: 22;
|
||||
width: parent.width - 200;
|
||||
selectByMouse: true;
|
||||
readOnly: true;
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.alignment: Qt.AlignRight;
|
||||
width: 225;
|
||||
height: parent.height;
|
||||
|
||||
SpinBox {
|
||||
id: spinbox;
|
||||
value: settingValue;
|
||||
from: minValue;
|
||||
to: maxValue;
|
||||
stepSize: stepSize;
|
||||
Layout.alignment: Qt.AlignRight;
|
||||
implicitWidth: 200;
|
||||
implicitHeight: parent.height;
|
||||
|
||||
contentItem: TextField {
|
||||
id: spinboxText;
|
||||
color: "white";
|
||||
text: parent.value;
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
width: parent.width;
|
||||
clip: true;
|
||||
font.pixelSize: 22
|
||||
validator: RegExpValidator { regExp: /[0-9]*/ }
|
||||
|
||||
background: Rectangle {
|
||||
color: "#111";
|
||||
border.width: 0;
|
||||
radius: 10;
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
valueChanged(spinboxText.text);
|
||||
settingValue = spinboxText.text;
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
valueChanged(spinboxText.text);
|
||||
settingValue = spinboxText.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
up.indicator: Button {
|
||||
height: parent.height - 15;
|
||||
width: parent.height;
|
||||
x: parent.width - width;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
|
||||
background: Rectangle {
|
||||
color: buttonColor;
|
||||
border.width: 0;
|
||||
radius: 10;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "+";
|
||||
color: "white";
|
||||
font.pixelSize: 28;
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
spinbox.value += stepSize;
|
||||
valueChanged(spinbox.value);
|
||||
}
|
||||
}
|
||||
|
||||
down.indicator: Button {
|
||||
height: parent.height - 15;
|
||||
width: parent.height;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
|
||||
background: Rectangle {
|
||||
color: buttonColor;
|
||||
border.width: 0;
|
||||
radius: 10;
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "-";
|
||||
color: "white";
|
||||
font.pixelSize: 28;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
spinbox.value -= stepSize;
|
||||
valueChanged(spinbox.value);
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Text {
|
||||
visible: suffixText != "";
|
||||
text: suffixText;
|
||||
color: "white";
|
||||
height: parent.height;
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
x: spinbox.width + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
propagateComposedEvents: true;
|
||||
|
||||
onPressed: {
|
||||
mouse.accepted = false
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
backgroundElement.color = "#333";
|
||||
buttonColor = "#444";
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundElement.color = "transparent";
|
||||
buttonColor = "#333";
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 50
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
142
scripts/system/settings/qml/SettingSlider.qml
Normal file
|
@ -0,0 +1,142 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.5
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
Item {
|
||||
id: root;
|
||||
property string settingText: "";
|
||||
property var settingValue: 0;
|
||||
|
||||
property real minValue: 0;
|
||||
property real maxValue: 9;
|
||||
property real sliderStepSize: 0.1;
|
||||
property int roundDisplay: 1;
|
||||
|
||||
signal sliderValueChanged(real value);
|
||||
|
||||
height: 50;
|
||||
width: parent.width;
|
||||
|
||||
Rectangle {
|
||||
id: backgroundElement;
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
color: "transparent";
|
||||
radius: 15;
|
||||
|
||||
RowLayout {
|
||||
width: parent.width - 10;
|
||||
height: parent.height;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
Layout.alignment: Qt.AlignTop;
|
||||
|
||||
TextEdit {
|
||||
id: settingTextElem
|
||||
height: parent.height;
|
||||
text: settingText;
|
||||
color: "white";
|
||||
font.pixelSize: 22;
|
||||
Layout.fillWidth: true;
|
||||
selectByMouse: true;
|
||||
readOnly: true;
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignRight;
|
||||
width: 225;
|
||||
implicitWidth: 225;
|
||||
height: parent.height;
|
||||
Layout.fillWidth: false;
|
||||
|
||||
Text {
|
||||
id: sliderValueDisplay
|
||||
text: slider.value.toFixed(roundDisplay);
|
||||
color: "white";
|
||||
height: parent.height;
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
width: 25;
|
||||
font.pixelSize: 22;
|
||||
}
|
||||
|
||||
Slider {
|
||||
Layout.fillWidth: true;
|
||||
height: parent.height;
|
||||
id: slider;
|
||||
from: minValue;
|
||||
to: maxValue;
|
||||
stepSize: sliderStepSize;
|
||||
snapMode: Slider.SnapOnRelease;
|
||||
value: settingValue;
|
||||
|
||||
handle: Rectangle {
|
||||
x: slider.leftPadding + slider.visualPosition * (slider.availableWidth - width)
|
||||
y: slider.topPadding + slider.availableHeight / 2 - height / 2
|
||||
implicitWidth: 20
|
||||
implicitHeight: 40
|
||||
color: "black"
|
||||
|
||||
Rectangle {
|
||||
width: 16
|
||||
height: 36
|
||||
color: "gray"
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
x: slider.leftPadding;
|
||||
y: slider.topPadding + slider.availableHeight / 2 - height / 2;
|
||||
implicitWidth: 200;
|
||||
implicitHeight: 20;
|
||||
width: slider.availableWidth;
|
||||
height: implicitHeight;
|
||||
radius: 10;
|
||||
color: "#ffffff";
|
||||
clip: true;
|
||||
|
||||
Rectangle {
|
||||
width: slider.visualPosition * parent.width + 1;
|
||||
height: parent.height + 1;
|
||||
color: "#5153bd";
|
||||
radius: parent.radius;
|
||||
antialiasing: false;
|
||||
}
|
||||
}
|
||||
|
||||
onValueChanged: {
|
||||
sliderValueChanged(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
propagateComposedEvents: true;
|
||||
|
||||
onPressed: {
|
||||
mouse.accepted = false
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
backgroundElement.color = "#333";
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundElement.color = "transparent";
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 50
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
92
scripts/system/settings/qml/SettingSubviewListElement.qml
Normal file
|
@ -0,0 +1,92 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.3
|
||||
import TabletScriptingInterface 1.0
|
||||
|
||||
Item {
|
||||
property color bgColor: index % 2 === 0 ? "transparent" : Qt.rgba(0.12,0.12,0.12,1);
|
||||
property int initialTextXPosition;
|
||||
|
||||
width: parent.width;
|
||||
height: 60;
|
||||
|
||||
Rectangle {
|
||||
id: backgroundElement;
|
||||
width: parent.width;
|
||||
height: parent.height;
|
||||
color: bgColor;
|
||||
anchors.fill: parent;
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 50
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width - 20;
|
||||
height: parent.height;
|
||||
anchors.centerIn: parent;
|
||||
|
||||
// Image/Icon container
|
||||
Item {
|
||||
width: 45;
|
||||
height: parent.height;
|
||||
|
||||
Image {
|
||||
sourceSize.height: 25;
|
||||
source: pageIcon;
|
||||
anchors.centerIn: parent;
|
||||
}
|
||||
}
|
||||
|
||||
// Page name
|
||||
Text {
|
||||
id: pageNameElement
|
||||
text: pageName;
|
||||
color: "white";
|
||||
font.pixelSize: 24;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
|
||||
// Set a variable to the initial X position, used for animating it on hover.
|
||||
Component.onCompleted: {
|
||||
initialTextXPosition = x;
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: 50
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
|
||||
onClicked: {
|
||||
Tablet.playSound(TabletEnums.ButtonClicked);
|
||||
if (targetPage !== "") {
|
||||
toScript({type:"switchApp", appUrl: targetPage});
|
||||
return;
|
||||
}
|
||||
currentPage = pageName;
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
backgroundElement.color = "#333";
|
||||
pageNameElement.x = initialTextXPosition + 20;
|
||||
Tablet.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
|
||||
onExited: {
|
||||
backgroundElement.color = bgColor;
|
||||
pageNameElement.x = initialTextXPosition;
|
||||
}
|
||||
}
|
||||
}
|
353
scripts/system/settings/qml/pages/GraphicsSettings.qml
Normal file
|
@ -0,0 +1,353 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.3
|
||||
import "../"
|
||||
|
||||
Flickable {
|
||||
property var verticalScrollBarWidth: 20;
|
||||
property bool hasPresetBeenModified: false;
|
||||
property bool isChangingPreset: false;
|
||||
|
||||
id: graphicsPage;
|
||||
visible: currentPage == "Graphics";
|
||||
width: parent.width;
|
||||
Layout.fillHeight: true;
|
||||
y: header.height + 10;
|
||||
contentWidth: parent.width;
|
||||
contentHeight: graphicsPageColumn.height;
|
||||
clip: true;
|
||||
flickDeceleration: 4000;
|
||||
|
||||
Timer {
|
||||
id: verticalScrollBarInitialVisibilityTimer;
|
||||
interval: 200;
|
||||
running: false;
|
||||
repeat: false;
|
||||
|
||||
onTriggered: {
|
||||
verticalScrollBarWidth = 15;
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
// Set the initial values for the variables.
|
||||
verticalScrollBarWidth = 20;
|
||||
|
||||
// We are leaving the page, don't animate.
|
||||
if (!visible) return;
|
||||
|
||||
// We have opened the page
|
||||
// Start the visibility effect timers.
|
||||
verticalScrollBarInitialVisibilityTimer.running = true;
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollBar;
|
||||
policy: Qt.ScrollBarAlwaysOn;
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: verticalScrollBarWidth;
|
||||
color: "transparent";
|
||||
radius: 5;
|
||||
visible: scrollBar.visible;
|
||||
|
||||
Behavior on implicitWidth {
|
||||
NumberAnimation {
|
||||
duration: 300;
|
||||
easing.type: Easing.InOutCubic;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: graphicsPageColumn;
|
||||
width: parent.width - 20;
|
||||
anchors.horizontalCenterOffset: -5
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
spacing: 10;
|
||||
|
||||
// Graphics Presets
|
||||
SettingComboBox {
|
||||
id: graphicsPresetCombobox;
|
||||
settingText: "Graphics preset";
|
||||
optionIndex: Performance.getPerformancePreset() - 1;
|
||||
options: ["Low Power", "Low", "Medium", "High", "Custom"];
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setPerformancePreset(index + 1);
|
||||
if (index !== 4) switchToAGraphicsPreset();
|
||||
}
|
||||
}
|
||||
|
||||
// Rendering Effects
|
||||
SettingBoolean {
|
||||
settingText: "Rendering effects";
|
||||
settingEnabledCondition: function () { return Render.renderMethod === 0; }
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
Render.renderMethod = settingEnabled ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Rendering Effects sub options
|
||||
AdvancedOptions {
|
||||
id: renderingEffectsAdvancedOptions;
|
||||
isEnabled: Render.renderMethod === 0;
|
||||
|
||||
SettingBoolean {
|
||||
settingText: "Shadows";
|
||||
settingEnabledCondition: () => { return Render.shadowsEnabled }
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
Render.shadowsEnabled = settingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
SettingBoolean {
|
||||
settingText: "Local Lights";
|
||||
settingEnabledCondition: () => { return Render.renderMethod === 0 }
|
||||
}
|
||||
|
||||
// NOTE: Once local lights have a proper toggle, the SettingBoolean above can be replaced with this one below.
|
||||
// SettingBoolean {
|
||||
// settingText: "Local Lights";
|
||||
// settingEnabledCondition: () => { return Render.localLightsEnabled }
|
||||
|
||||
// onSettingEnabledChanged: {
|
||||
// Render.localLightsEnabled = settingEnabled;
|
||||
// }
|
||||
// }
|
||||
|
||||
SettingBoolean {
|
||||
settingText: "Ambient Occlusion";
|
||||
settingEnabledCondition: () => { return Render.ambientOcclusionEnabled }
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
Render.ambientOcclusionEnabled = settingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
SettingBoolean {
|
||||
settingText: "Haze";
|
||||
settingEnabledCondition: () => { return Render.hazeEnabled }
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
Render.hazeEnabled = settingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
SettingBoolean {
|
||||
settingText: "Bloom";
|
||||
settingEnabledCondition: () => { return Render.bloomEnabled }
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
Render.bloomEnabled = settingEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Procedural Materials
|
||||
SettingBoolean {
|
||||
settingText: "Procedural Materials";
|
||||
settingEnabledCondition: () => { return Render.proceduralMaterialsEnabled}
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
Render.proceduralMaterialsEnabled = settingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
// FPS
|
||||
SettingComboBox {
|
||||
settingText: "Refresh rate";
|
||||
options: ["Economical", "Interactive", "Real-Time", "Custom"];
|
||||
optionIndex: Performance.getRefreshRateProfile();
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setRefreshRateProfile(index);
|
||||
fpsAdvancedOptions.isEnabled = index == 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom FPS
|
||||
AdvancedOptions {
|
||||
id: fpsAdvancedOptions;
|
||||
isEnabled: Performance.getRefreshRateProfile() === 3;
|
||||
|
||||
SettingNumber {
|
||||
settingText: "Focus Active";
|
||||
minValue: 5;
|
||||
maxValue: 9999;
|
||||
suffixText: "fps";
|
||||
settingValue: Performance.getCustomRefreshRate(0)
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setCustomRefreshRate(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
SettingNumber {
|
||||
settingText: "Focus Inactive";
|
||||
minValue: 1;
|
||||
maxValue: 9999;
|
||||
suffixText: "fps";
|
||||
settingValue: Performance.getCustomRefreshRate(1)
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setCustomRefreshRate(1, value);
|
||||
}
|
||||
}
|
||||
|
||||
SettingNumber {
|
||||
settingText: "Unfocused";
|
||||
minValue: 1;
|
||||
maxValue: 9999;
|
||||
suffixText: "fps";
|
||||
settingValue: Performance.getCustomRefreshRate(2)
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setCustomRefreshRate(2, value);
|
||||
}
|
||||
}
|
||||
|
||||
SettingNumber {
|
||||
settingText: "Minimized";
|
||||
minValue: 1;
|
||||
maxValue: 9999;
|
||||
suffixText: "fps";
|
||||
settingValue: Performance.getCustomRefreshRate(3)
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setCustomRefreshRate(3, value);
|
||||
}
|
||||
}
|
||||
|
||||
SettingNumber {
|
||||
settingText: "Startup";
|
||||
minValue: 1;
|
||||
maxValue: 9999;
|
||||
suffixText: "fps";
|
||||
settingValue: Performance.getCustomRefreshRate(4)
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setCustomRefreshRate(4, value);
|
||||
}
|
||||
}
|
||||
|
||||
SettingNumber {
|
||||
settingText: "Shutdown";
|
||||
minValue: 1;
|
||||
maxValue: 9999;
|
||||
suffixText: "fps";
|
||||
settingValue: Performance.getCustomRefreshRate(5)
|
||||
|
||||
onValueChanged: {
|
||||
Performance.setCustomRefreshRate(5, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolution Scale
|
||||
SettingSlider {
|
||||
settingText: "Resolution scale";
|
||||
sliderStepSize: 0.1;
|
||||
minValue: 0.1;
|
||||
maxValue: 2;
|
||||
settingValue: Render.viewportResolutionScale.toFixed(1)
|
||||
|
||||
onSliderValueChanged: {
|
||||
Render.viewportResolutionScale = value.toFixed(1)
|
||||
}
|
||||
}
|
||||
|
||||
// Fullscreen Display
|
||||
SettingComboBox {
|
||||
settingText: "Fullscreen Display";
|
||||
|
||||
Component.onCompleted: {
|
||||
var screens = Render.getScreens();
|
||||
var selected = Render.getFullScreenScreen();
|
||||
setOptions(screens);
|
||||
|
||||
for (let i = 0; screens.length > i; i++) {
|
||||
if (screens[i] == selected) {
|
||||
optionIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onValueChanged: {
|
||||
Render.setFullScreenScreen(optionText);
|
||||
}
|
||||
}
|
||||
|
||||
// FOV
|
||||
SettingSlider {
|
||||
settingText: "Field of View";
|
||||
sliderStepSize: 1;
|
||||
minValue: 20;
|
||||
maxValue: 130;
|
||||
settingValue: Render.verticalFieldOfView.toFixed(1);
|
||||
roundDisplay: 0;
|
||||
|
||||
onSliderValueChanged: {
|
||||
Render.verticalFieldOfView = value.toFixed(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Camera clipping
|
||||
SettingBoolean {
|
||||
settingText: "Allow camera clipping";
|
||||
settingEnabledCondition: () => { return !Render.cameraClippingEnabled }
|
||||
|
||||
onSettingEnabledChanged: {
|
||||
Render.cameraClippingEnabled = settingEnabled ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Anti Aliasing
|
||||
SettingComboBox {
|
||||
settingText: "Anti-aliasing";
|
||||
optionIndex: Render.antialiasingMode;
|
||||
options: ["None", "TAA", "FXAA"];
|
||||
|
||||
onValueChanged: {
|
||||
Render.antialiasingMode = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onHasPresetBeenModifiedChanged: {
|
||||
if (hasPresetBeenModified === true && isChangingPreset === false){
|
||||
graphicsPresetCombobox.setOptionIndex(4);
|
||||
}
|
||||
}
|
||||
|
||||
function switchToAGraphicsPreset(){
|
||||
// We need to disable the event updates from settings to detect if we have changed a preset.
|
||||
isChangingPreset = true;
|
||||
|
||||
// Change all of the settings to match the preset
|
||||
recursivelyUpdateAllSettings(graphicsPageColumn);
|
||||
hasPresetBeenModified = false;
|
||||
|
||||
// "Unmute" the events listening for a preset change.
|
||||
isChangingPreset = false;
|
||||
}
|
||||
|
||||
function recursivelyUpdateAllSettings(item){
|
||||
// In order to update all settings based on current values,
|
||||
// we need to go through all children elements and re-evaluate their settingEnabled value
|
||||
|
||||
// Update all settings options visually to reflect settings
|
||||
for (let i = 0; item.children.length > i; i++) {
|
||||
var child = item.children[i];
|
||||
|
||||
child.update();
|
||||
|
||||
// Run this function on all of this elements children.
|
||||
recursivelyUpdateAllSettings(child);
|
||||
}
|
||||
}
|
||||
}
|
96
scripts/system/settings/settings.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
//
|
||||
// settings.js
|
||||
//
|
||||
// App to configure Overte
|
||||
//
|
||||
// Created by Armored Dragon, 2024.
|
||||
// Copyright 2024-2025 Overte e.V.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global Script Tablet */
|
||||
|
||||
(() => {
|
||||
"use strict";
|
||||
var tablet;
|
||||
var appButton;
|
||||
var active = false;
|
||||
const url = Script.resolvePath("./Settings.qml")
|
||||
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
appButton = tablet.addButton({
|
||||
icon: Script.resolvePath("./img/icon_white.png"),
|
||||
activeIcon: Script.resolvePath("./img/icon_black.png"),
|
||||
text: "SETTINGS",
|
||||
isActive: active,
|
||||
});
|
||||
|
||||
// When script ends, remove itself from tablet
|
||||
Script.scriptEnding.connect(function () {
|
||||
console.log("Shutting down Settings.js application");
|
||||
tablet.removeButton(appButton);
|
||||
Menu.removeMenuItem("Settings", "Graphics...");
|
||||
});
|
||||
|
||||
// Event listeners
|
||||
appButton.clicked.connect(toolbarButtonClicked);
|
||||
tablet.fromQml.connect(fromQML);
|
||||
tablet.screenChanged.connect(onTabletScreenChanged);
|
||||
Menu.menuItemEvent.connect(onMenuItemEvent);
|
||||
|
||||
// Menu button
|
||||
Menu.addMenuItem({
|
||||
menuName: "Settings",
|
||||
menuItemName: "Graphics...",
|
||||
afterItem: "Audio...",
|
||||
});
|
||||
|
||||
function onMenuItemEvent(menuItem) {
|
||||
if (menuItem === 'Graphics...') {
|
||||
toolbarButtonClicked();
|
||||
toQML({ type: 'loadPage', page: 'Graphics' })
|
||||
}
|
||||
}
|
||||
|
||||
function toolbarButtonClicked() {
|
||||
if (active) tablet.gotoHomeScreen();
|
||||
else tablet.loadQMLSource(url);
|
||||
|
||||
active = !active;
|
||||
appButton.editProperties({
|
||||
isActive: active,
|
||||
});
|
||||
}
|
||||
|
||||
function onTabletScreenChanged(type, newUrl) {
|
||||
if (url == newUrl) active = true;
|
||||
else active = false;
|
||||
|
||||
appButton.editProperties({
|
||||
isActive: active,
|
||||
});
|
||||
}
|
||||
|
||||
// Communication
|
||||
function fromQML(event) {
|
||||
console.log(`New QML event:\n${JSON.stringify(event)}`);
|
||||
|
||||
if (event.type === "switchApp") {
|
||||
if (event.appUrl == "hifi/dialogs/GeneralPreferencesDialog.qml") {
|
||||
// This page needs to be opened like this just because.
|
||||
Desktop.show("hifi/dialogs/GeneralPreferencesDialog.qml", "GeneralPreferencesDialog");
|
||||
return;
|
||||
}
|
||||
tablet.loadQMLSource(event.appUrl);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Emit a packet to the HTML front end. Easy communication!
|
||||
* @param {Object} packet - The Object packet to emit to the HTML
|
||||
* @param {("loadPage"|)} packet.type - The type of packet it is
|
||||
*/
|
||||
function toQML(packet = { type: "" }) {
|
||||
tablet.sendToQml(packet);
|
||||
}
|
||||
})();
|