mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
First pass on preferences dialog
Conflicts: tests/ui/qmlscratch.pro
This commit is contained in:
parent
6cd6c3038f
commit
205ab05506
14 changed files with 991 additions and 3 deletions
82
interface/resources/qml/hifi/dialogs/PreferencesDialog.qml
Normal file
82
interface/resources/qml/hifi/dialogs/PreferencesDialog.qml
Normal file
|
@ -0,0 +1,82 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../controls" as HifiControls
|
||||
import "../../windows"
|
||||
import "./preferences"
|
||||
|
||||
Window {
|
||||
id: root
|
||||
objectName: "Preferences"
|
||||
title: "Preferences"
|
||||
resizable: true
|
||||
destroyOnInvisible: true
|
||||
width: 500
|
||||
height: 577
|
||||
property var sections: []
|
||||
|
||||
function saveAll() {
|
||||
for (var i = 0; i < sections.length; ++i) {
|
||||
var section = sections[i];
|
||||
section.saveAll();
|
||||
}
|
||||
destroy();
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
color: "white"
|
||||
|
||||
Settings {
|
||||
category: "Overlay.Preferences"
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
}
|
||||
|
||||
Component {
|
||||
id: sectionBuilder
|
||||
Section { }
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Preferences.loadAll();
|
||||
var categories = Preferences.categories;
|
||||
for (var i = 0; i < categories.length; ++i) {
|
||||
var category = categories[i];
|
||||
sections.push(sectionBuilder.createObject(prefControls, { name: category }));
|
||||
}
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: flickable
|
||||
clip: true
|
||||
interactive: true
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: dialogButtons.top
|
||||
anchors.bottomMargin: 8
|
||||
contentHeight: prefControls.height
|
||||
contentWidth: parent.width
|
||||
|
||||
Column {
|
||||
id: prefControls
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
Row {
|
||||
id: dialogButtons
|
||||
anchors { bottom: parent.bottom; right: parent.right; margins: 8 }
|
||||
Button { text: "Cancel"; onClicked: root.destroy(); }
|
||||
Button {
|
||||
text: "Save all changes"
|
||||
onClicked: root.saveAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
import "."
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property alias buttonText: button.text
|
||||
property alias text: dataTextField.text
|
||||
property alias placeholderText: dataTextField.placeholderText
|
||||
property real spacing: 8
|
||||
height: labelText.height + Math.max(dataTextField.height, button.height) + spacing
|
||||
|
||||
Component.onCompleted: {
|
||||
dataTextField.text = preference.value;
|
||||
}
|
||||
|
||||
function save() {
|
||||
preference.value = dataTextField.text;
|
||||
preference.save();
|
||||
}
|
||||
|
||||
Text {
|
||||
id: labelText
|
||||
text: root.label
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: dataTextField
|
||||
placeholderText: root.placeholderText
|
||||
text: preference.value
|
||||
anchors {
|
||||
top: labelText.bottom
|
||||
left: parent.left
|
||||
right: button.left
|
||||
topMargin: root.spacing
|
||||
rightMargin: root.spacing
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: button
|
||||
anchors {
|
||||
right: parent.right;
|
||||
verticalCenter: dataTextField.verticalCenter
|
||||
}
|
||||
text: "Browse"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import "."
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
height: checkBox.implicitHeight
|
||||
|
||||
Component.onCompleted: {
|
||||
checkBox.checked = preference.value;
|
||||
}
|
||||
|
||||
function save() {
|
||||
preference.value = checkBox.checked;
|
||||
preference.save();
|
||||
}
|
||||
|
||||
Original.CheckBox {
|
||||
id: checkBox
|
||||
anchors.fill: parent
|
||||
text: root.label
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property real spacing: 8
|
||||
height: labelText.height + dataTextField.height + spacing
|
||||
|
||||
Component.onCompleted: {
|
||||
dataTextField.text = preference.value;
|
||||
}
|
||||
|
||||
function save() {
|
||||
preference.value = dataTextField.text;
|
||||
preference.save();
|
||||
}
|
||||
|
||||
Text {
|
||||
id: labelText
|
||||
text: root.label
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: dataTextField
|
||||
placeholderText: preference.placeholderText
|
||||
anchors {
|
||||
top: labelText.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
topMargin: root.spacing
|
||||
rightMargin: root.spacing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors { left: parent.left; right: parent.right }
|
||||
property var preference;
|
||||
property string label: preference ? preference.name : "";
|
||||
}
|
114
interface/resources/qml/hifi/dialogs/preferences/Section.qml
Normal file
114
interface/resources/qml/hifi/dialogs/preferences/Section.qml
Normal file
|
@ -0,0 +1,114 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import Hifi 1.0
|
||||
|
||||
import "../../../controls" as VrControls
|
||||
import "."
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property bool expanded: false
|
||||
property string name: "Header"
|
||||
property real spacing: 8
|
||||
readonly property alias toggle: toggle
|
||||
readonly property alias header: header
|
||||
default property alias preferences: contentContainer.children
|
||||
|
||||
function saveAll() {
|
||||
for (var i = 0; i < d.preferences.length; ++i) {
|
||||
var preference = d.preferences[i];
|
||||
preference.save();
|
||||
}
|
||||
}
|
||||
|
||||
clip: true
|
||||
children: [ toggle, header, contentContainer ]
|
||||
height: expanded ? header.height + contentContainer.height + root.spacing * 3
|
||||
: Math.max(toggle.height, header.height) + root.spacing * 2
|
||||
Behavior on height { PropertyAnimation {} }
|
||||
|
||||
Component.onCompleted: d.buildPreferences();
|
||||
|
||||
function toggleExpanded() {
|
||||
root.expanded = !root.expanded;
|
||||
}
|
||||
|
||||
VrControls.FontAwesome {
|
||||
id: toggle
|
||||
anchors { left: parent.left; top: parent.top; margins: root.spacing }
|
||||
rotation: root.expanded ? 0 : -90
|
||||
text: "\uf078"
|
||||
Behavior on rotation { PropertyAnimation {} }
|
||||
MouseArea { anchors.fill: parent; onClicked: root.toggleExpanded() }
|
||||
}
|
||||
|
||||
Text {
|
||||
id: header
|
||||
anchors { left: toggle.right; top: parent.top; leftMargin: root.spacing * 2; margins: root.spacing }
|
||||
font.bold: true
|
||||
font.pointSize: 16
|
||||
color: "#0e7077"
|
||||
text: root.name
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentContainer
|
||||
spacing: root.spacing
|
||||
anchors { left: toggle.right; top: header.bottom; topMargin: root.spacing; right: parent.right; margins: root.spacing }
|
||||
enabled: root.expanded
|
||||
visible: root.expanded
|
||||
clip: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var editableBuilder: Component { Editable { } }
|
||||
property var browsableBuilder: Component { Browsable { } }
|
||||
property var spinnerBuilder: Component { SpinBox { } }
|
||||
property var checkboxBuilder: Component { CheckBox { } }
|
||||
property var sliderBuilder: Component { Slider { } }
|
||||
property var preferences: []
|
||||
|
||||
function buildPreferences() {
|
||||
var categoryPreferences = Preferences.preferencesByCategory[root.name];
|
||||
if (categoryPreferences) {
|
||||
console.log("Category " + root.name + " with " + categoryPreferences.length + " preferences");
|
||||
for (var j = 0; j < categoryPreferences.length; ++j) {
|
||||
buildPreference(categoryPreferences[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildPreference(preference) {
|
||||
console.log("\tPreference type " + preference.type + " name " + preference.name)
|
||||
var builder;
|
||||
switch (preference.type) {
|
||||
case Preference.Editable:
|
||||
builder = editableBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Browsable:
|
||||
builder = browsableBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Spinner:
|
||||
builder = spinnerBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Slider:
|
||||
builder = sliderBuilder;
|
||||
break;
|
||||
|
||||
case Preference.Checkbox:
|
||||
builder = checkboxBuilder;
|
||||
break;
|
||||
|
||||
};
|
||||
|
||||
if (builder) {
|
||||
preferences.push(builder.createObject(contentContainer, { preference: preference }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
32
interface/resources/qml/hifi/dialogs/preferences/Slider.qml
Normal file
32
interface/resources/qml/hifi/dialogs/preferences/Slider.qml
Normal file
|
@ -0,0 +1,32 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
|
||||
import "."
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property alias slider: slider
|
||||
height: slider.height
|
||||
|
||||
Component.onCompleted: {
|
||||
slider.value = preference.value;
|
||||
}
|
||||
|
||||
function save() {
|
||||
preference.value = slider.value;
|
||||
preference.save();
|
||||
}
|
||||
|
||||
|
||||
Text {
|
||||
text: root.label
|
||||
anchors.verticalCenter: slider.verticalCenter
|
||||
}
|
||||
|
||||
Original.Slider {
|
||||
id: slider
|
||||
value: preference.value
|
||||
width: 130
|
||||
anchors { right: parent.right }
|
||||
}
|
||||
}
|
33
interface/resources/qml/hifi/dialogs/preferences/SpinBox.qml
Normal file
33
interface/resources/qml/hifi/dialogs/preferences/SpinBox.qml
Normal file
|
@ -0,0 +1,33 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4 as Original
|
||||
import "."
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property alias spinner: spinner
|
||||
height: spinner.height
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
spinner.value = preference.value;
|
||||
}
|
||||
|
||||
function save() {
|
||||
preference.value = spinner.value;
|
||||
preference.save();
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.label
|
||||
anchors.verticalCenter: spinner.verticalCenter
|
||||
}
|
||||
|
||||
Original.SpinBox {
|
||||
id: spinner
|
||||
decimals: preference.decimals
|
||||
minimumValue: preference.min
|
||||
maximumValue: preference.max
|
||||
width: 100
|
||||
anchors { right: parent.right }
|
||||
}
|
||||
}
|
|
@ -1175,7 +1175,7 @@ void Application::initializeGL() {
|
|||
|
||||
InfoView::show(INFO_HELP_PATH, true);
|
||||
}
|
||||
|
||||
extern void setupPreferences();
|
||||
void Application::initializeUi() {
|
||||
AddressBarDialog::registerType();
|
||||
ErrorDialog::registerType();
|
||||
|
@ -1201,6 +1201,8 @@ void Application::initializeUi() {
|
|||
qApp->quit();
|
||||
});
|
||||
|
||||
setupPreferences();
|
||||
|
||||
// For some reason there is already an "Application" object in the QML context,
|
||||
// though I can't find it. Hence, "ApplicationInterface"
|
||||
rootContext->setContextProperty("ApplicationInterface", this);
|
||||
|
@ -1833,6 +1835,14 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_X:
|
||||
if (isShifted && isMeta) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->getRootContext()->engine()->clearComponentCache();
|
||||
offscreenUi->show(QString("hifi/dialogs/PreferencesDialog.qml"), "PreferencesDialog");
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_B:
|
||||
if (isMeta) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include <devices/Faceshift.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <QtQml/QQmlContext>
|
||||
#include <Preferences.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "DialogsManager.h"
|
||||
|
@ -30,6 +33,291 @@
|
|||
#include "UIUtil.h"
|
||||
#include "scripting/WebWindowClass.h"
|
||||
|
||||
void setupPreferences() {
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
|
||||
Preferences* preferences = new Preferences();
|
||||
|
||||
static const QString AVATAR_BASICS { "Avatar Basics" };
|
||||
{
|
||||
auto getter = [=]()->QString {return myAvatar->getDisplayName(); };
|
||||
auto setter = [=](const QString& value) { myAvatar->setDisplayName(value); };
|
||||
const QString label = "Avatar display name <font color=\"#909090\">(optional)</font>";
|
||||
auto preference = new EditPreference(AVATAR_BASICS, label, getter, setter, preferences);
|
||||
preference->setPlaceholderText("Not showing a name");
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = [=]()->QString {return myAvatar->getCollisionSoundURL(); };
|
||||
auto setter = [=](const QString& value) { myAvatar->setCollisionSoundURL(value); };
|
||||
const QString label = "Avatar collision sound URL <font color=\"#909090\">(optional)</font>";
|
||||
auto preference = new EditPreference(AVATAR_BASICS, label, getter, setter, preferences);
|
||||
preference->setPlaceholderText("Enter the URL of a sound to play when you bump into something");
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = [=]()->QString { return myAvatar->getFullAvatarURLFromPreferences().toString(); };
|
||||
auto setter = [=](const QString& value) { /* FIXME */ };
|
||||
auto preference = new BrowsePreference(AVATAR_BASICS, "Appearance: ", getter, setter, preferences);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = []()->QString { return Snapshot::snapshotsLocation.get(); };
|
||||
auto setter = [](const QString& value) { Snapshot::snapshotsLocation.set(value); };
|
||||
auto preference = new BrowsePreference("Snapshots", "Place my Snapshots here:", getter, setter, preferences);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
// Scripts
|
||||
{
|
||||
auto getter = []()->QString { return DependencyManager::get<ScriptEngines>()->getScriptsLocation(); };
|
||||
auto setter = [](const QString& value) { DependencyManager::get<ScriptEngines>()->setScriptsLocation(value); };
|
||||
preferences->addPreference(new BrowsePreference("Scripts", "Load scripts from this directory:", getter, setter, preferences));
|
||||
}
|
||||
|
||||
preferences->addPreference(new ButtonPreference("Scripts", "Load Default Scripts", preferences));
|
||||
|
||||
|
||||
{
|
||||
auto getter = []()->bool {return !Menu::getInstance()->isOptionChecked(MenuOption::DisableActivityLogger); };
|
||||
auto setter = [](bool value) { Menu::getInstance()->setIsOptionChecked(MenuOption::DisableActivityLogger, !value); };
|
||||
preferences->addPreference(new CheckPreference("Privacy", "Send Data", getter, setter, preferences));
|
||||
}
|
||||
|
||||
static const QString LOD_TUNING("Level of Detail Tuning");
|
||||
{
|
||||
auto getter = []()->bool { return DependencyManager::get<LODManager>()->getUseAcuity(); };
|
||||
auto setter = [](bool value) { DependencyManager::get<LODManager>()->setUseAcuity(value); };
|
||||
preferences->addPreference(new CheckPreference(LOD_TUNING, "Render based on visual acuity", getter, setter, preferences));
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<LODManager>()->getDesktopLODDecreaseFPS(); };
|
||||
auto setter = [](float value) { DependencyManager::get<LODManager>()->setDesktopLODDecreaseFPS(value); };
|
||||
auto preference = new SpinnerPreference(LOD_TUNING, "Minimum Desktop FPS", getter, setter, preferences);
|
||||
preference->setMin(0);
|
||||
preference->setMax(120);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<LODManager>()->getHMDLODDecreaseFPS(); };
|
||||
auto setter = [](float value) { DependencyManager::get<LODManager>()->setHMDLODDecreaseFPS(value); };
|
||||
auto preference = new SpinnerPreference(LOD_TUNING, "Minimum HMD FPS", getter, setter, preferences);
|
||||
preference->setMin(0);
|
||||
preference->setMax(120);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = []()->float { return 1.0f / DependencyManager::get<LODManager>()->getRenderDistanceInverseHighLimit(); };
|
||||
auto setter = [](float value) { DependencyManager::get<LODManager>()->setRenderDistanceInverseHighLimit(1.0f / value); };
|
||||
auto preference = new SpinnerPreference(LOD_TUNING, "Minimum Display Distance", getter, setter, preferences);
|
||||
preference->setMin(5);
|
||||
preference->setMax(32768);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
static const QString AVATAR_TUNING { "Avatar Tuning" };
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getRealWorldFieldOfView(); };
|
||||
auto setter = [=](float value) { myAvatar->setRealWorldFieldOfView(value); };
|
||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Real world vertical field of view (angular size of monitor)", getter, setter, preferences);
|
||||
preference->setMin(1);
|
||||
preference->setMax(180);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return qApp->getFieldOfView(); };
|
||||
auto setter = [](float value) { qApp->setFieldOfView(value); };
|
||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Vertical field of view", getter, setter, preferences);
|
||||
preference->setMin(1);
|
||||
preference->setMax(180);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getLeanScale(); };
|
||||
auto setter = [=](float value) { myAvatar->setLeanScale(value); };
|
||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Lean scale (applies to Faceshift users)", getter, setter, preferences);
|
||||
preference->setMin(0);
|
||||
preference->setMax(99.9f);
|
||||
preference->setDecimals(2);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getUniformScale(); };
|
||||
auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell?
|
||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale <font color=\"#909090\">(default is 1.0)</font>", getter, setter, preferences);
|
||||
preference->setMin(0.01f);
|
||||
preference->setMax(99.9f);
|
||||
preference->setDecimals(2);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getHead()->getPupilDilation(); };
|
||||
auto setter = [=](float value) { myAvatar->getHead()->setPupilDilation(value); };
|
||||
preferences->addPreference(new SliderPreference(AVATAR_TUNING, "Pupil dilation", getter, setter, preferences));
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<DdeFaceTracker>()->getEyeClosingThreshold(); };
|
||||
auto setter = [](float value) { DependencyManager::get<DdeFaceTracker>()->setEyeClosingThreshold(value); };
|
||||
preferences->addPreference(new SliderPreference(AVATAR_TUNING, "Camera binary eyelid threshold", getter, setter, preferences));
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return FaceTracker::getEyeDeflection(); };
|
||||
auto setter = [](float value) { FaceTracker::setEyeDeflection(value); };
|
||||
preferences->addPreference(new SliderPreference(AVATAR_TUNING, "Face tracker eye deflection", getter, setter, preferences));
|
||||
}
|
||||
{
|
||||
auto getter = []()->QString { return DependencyManager::get<Faceshift>()->getHostname(); };
|
||||
auto setter = [](const QString& value) { DependencyManager::get<Faceshift>()->setHostname(value); };
|
||||
auto preference = new EditPreference(AVATAR_TUNING, "Faceshift hostname", getter, setter, preferences);
|
||||
preference->setPlaceholderText("localhost");
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->QString { return myAvatar->getAnimGraphUrl().toString(); };
|
||||
auto setter = [=](const QString& value) { myAvatar->setAnimGraphUrl(value); };
|
||||
auto preference = new EditPreference(AVATAR_TUNING, "Avatar Animation JSON", getter, setter, preferences);
|
||||
preference->setPlaceholderText("default");
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
static const QString AUDIO("Audio");
|
||||
{
|
||||
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getDynamicJitterBuffers(); };
|
||||
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setDynamicJitterBuffers(value); };
|
||||
preferences->addPreference(new CheckPreference(AUDIO, "Enable Dynamic Jitter Buffers", getter, setter, preferences));
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getDesiredJitterBufferFrames(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setStaticDesiredJitterBufferFrames(value); };
|
||||
|
||||
auto preference = new SpinnerPreference(AUDIO, "Static Jitter Buffer Frames", getter, setter, preferences);
|
||||
preference->setMin(0);
|
||||
preference->setMax(10000);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getMaxFramesOverDesired(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setMaxFramesOverDesired(value); };
|
||||
auto preference = new SpinnerPreference(AUDIO, "Max Frames Over Desired", getter, setter, preferences);
|
||||
preference->setMax(10000);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getUseStDevForJitterCalc(); };
|
||||
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setUseStDevForJitterCalc(value); };
|
||||
preferences->addPreference(new CheckPreference(AUDIO, "Use Stddev for Dynamic Jitter Calc", getter, setter, preferences));
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowStarveThreshold(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowStarveThreshold(value); };
|
||||
auto preference = new SpinnerPreference(AUDIO, "Window A Starve Threshold", getter, setter, preferences);
|
||||
preference->setMax(10000);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowSecondsForDesiredCalcOnTooManyStarves(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowSecondsForDesiredCalcOnTooManyStarves(value); };
|
||||
auto preference = new SpinnerPreference(AUDIO, "Window A (raise desired on N starves) Seconds)", getter, setter, preferences);
|
||||
preference->setMax(10000);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getWindowSecondsForDesiredReduction(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setWindowSecondsForDesiredReduction(value); };
|
||||
auto preference = new SpinnerPreference(AUDIO, "Window B (desired ceiling) Seconds", getter, setter, preferences);
|
||||
preference->setMax(10000);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getReceivedAudioStream().getRepetitionWithFade(); };
|
||||
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->getReceivedAudioStream().setRepetitionWithFade(value); };
|
||||
preferences->addPreference(new CheckPreference(AUDIO, "Repetition with Fade", getter, setter, preferences));
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputBufferSize(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputBufferSize(value); };
|
||||
auto preference = new SpinnerPreference(AUDIO, "Output Buffer Size (frames)", getter, setter, preferences);
|
||||
preference->setMin(1);
|
||||
preference->setMax(20);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->bool {return DependencyManager::get<AudioClient>()->getOutputStarveDetectionEnabled(); };
|
||||
auto setter = [](bool value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionEnabled(value); };
|
||||
auto preference = new CheckPreference(AUDIO, "Output Starve Detection (Automatic Buffer Size Increase)", getter, setter, preferences);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputStarveDetectionThreshold(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionThreshold(value); };
|
||||
auto preference = new SpinnerPreference(AUDIO, "Output Starve Detection Threshold", getter, setter, preferences);
|
||||
preference->setMin(1);
|
||||
preference->setMax(500);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
{
|
||||
auto getter = []()->float { return DependencyManager::get<AudioClient>()->getOutputStarveDetectionPeriod(); };
|
||||
auto setter = [](float value) { DependencyManager::get<AudioClient>()->setOutputStarveDetectionPeriod(value); };
|
||||
auto preference = new SpinnerPreference(AUDIO, "Output Starve Detection Period (ms)", getter, setter, preferences);
|
||||
preference->setMin(1);
|
||||
preference->setMax(999999999);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
{
|
||||
auto getter = []()->float { return qApp->getMaxOctreePacketsPerSecond(); };
|
||||
auto setter = [](float value) { qApp->setMaxOctreePacketsPerSecond(value); };
|
||||
auto preference = new SpinnerPreference("Octree", "Max packets sent each second", getter, setter, preferences);
|
||||
preference->setMin(60);
|
||||
preference->setMax(6000);
|
||||
preference->setStep(10);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto getter = []()->float { return qApp->getApplicationCompositor().getHmdUIAngularSize(); };
|
||||
auto setter = [](float value) { qApp->getApplicationCompositor().setHmdUIAngularSize(value); };
|
||||
auto preference = new SpinnerPreference("HMD", "User Interface Horizontal Angular Size (degrees)", getter, setter, preferences);
|
||||
preference->setMin(30);
|
||||
preference->setMax(160);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
auto getter = []()->float { return controller::InputDevice::getReticleMoveSpeed(); };
|
||||
auto setter = [](float value) { controller::InputDevice::setReticleMoveSpeed(value); };
|
||||
auto preference = new SpinnerPreference("Sixense Controllers", "Reticle Movement Speed", getter, setter, preferences);
|
||||
preference->setMin(0);
|
||||
preference->setMax(100);
|
||||
preference->setStep(1);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
DependencyManager::get<OffscreenUi>()->getRootContext()->setContextProperty("Preferences", preferences);
|
||||
}
|
||||
|
||||
const int PREFERENCES_HEIGHT_PADDING = 20;
|
||||
|
||||
|
|
25
libraries/shared/src/Preferences.cpp
Normal file
25
libraries/shared/src/Preferences.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2016/01/20
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Preferences.h"
|
||||
|
||||
|
||||
void Preferences::addPreference(Preference* preference) {
|
||||
const QString& category = preference->getCategory();
|
||||
QVariantList categoryPreferences;
|
||||
// FIXME is there an easier way to do this with less copying?
|
||||
if (_preferencesByCategory.contains(category)) {
|
||||
categoryPreferences = qvariant_cast<QVariantList>(_preferencesByCategory[category]);
|
||||
} else {
|
||||
// Use this property to maintain the order of the categories
|
||||
_categories.append(category);
|
||||
}
|
||||
categoryPreferences.append(QVariant::fromValue(preference));
|
||||
_preferencesByCategory[category] = categoryPreferences;
|
||||
}
|
||||
|
248
libraries/shared/src/Preferences.h
Normal file
248
libraries/shared/src/Preferences.h
Normal file
|
@ -0,0 +1,248 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis 2016/01/20
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_Shared_Preferences_h
|
||||
#define hifi_Shared_Preferences_h
|
||||
|
||||
#include <functional>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QString>
|
||||
|
||||
class Preference;
|
||||
|
||||
class Preferences : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QVariantMap preferencesByCategory READ getPreferencesByCategory CONSTANT)
|
||||
Q_PROPERTY(QList<QString> categories READ getCategories CONSTANT)
|
||||
|
||||
public:
|
||||
void addPreference(Preference* preference);
|
||||
const QVariantMap& getPreferencesByCategory() { return _preferencesByCategory; }
|
||||
const QList<QString>& getCategories() { return _categories; }
|
||||
|
||||
private:
|
||||
QVariantMap _preferencesByCategory;
|
||||
QList<QString> _categories;
|
||||
};
|
||||
|
||||
class Preference : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString category READ getCategory CONSTANT)
|
||||
Q_PROPERTY(QString name READ getName CONSTANT)
|
||||
Q_PROPERTY(Type type READ getType CONSTANT)
|
||||
Q_PROPERTY(bool enabled READ isEnabled NOTIFY enabledChanged)
|
||||
Q_ENUMS(Type)
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
Invalid,
|
||||
Editable,
|
||||
Browsable,
|
||||
Slider,
|
||||
Spinner,
|
||||
Checkbox,
|
||||
Button,
|
||||
};
|
||||
|
||||
explicit Preference(QObject* parent = nullptr) : QObject(parent) {}
|
||||
Preference(const QString& category, const QString& name, QObject* parent = nullptr)
|
||||
: QObject(parent), _category(category), _name(name) { }
|
||||
|
||||
const QString& getCategory() const { return _category; }
|
||||
const QString& getName() const { return _name; }
|
||||
bool isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void setEnabled(bool enabled) {
|
||||
if (enabled != _enabled) {
|
||||
_enabled = enabled;
|
||||
emit enabledChanged();
|
||||
}
|
||||
}
|
||||
|
||||
virtual Type getType() { return Invalid; };
|
||||
|
||||
Q_INVOKABLE virtual void load() {};
|
||||
Q_INVOKABLE virtual void save() const {}
|
||||
|
||||
signals:
|
||||
void enabledChanged();
|
||||
|
||||
protected:
|
||||
virtual void emitValueChanged() {};
|
||||
|
||||
const QString _category;
|
||||
const QString _name;
|
||||
bool _enabled { true };
|
||||
};
|
||||
|
||||
class ButtonPreference : public Preference {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ButtonPreference(const QString& category, const QString& name, Preferences* parent = nullptr)
|
||||
: Preference(category, name, parent) { }
|
||||
Type getType() { return Button; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class TypedPreference : public Preference {
|
||||
public:
|
||||
using Getter = std::function<T()>;
|
||||
using Setter = std::function<void(const T&)>;
|
||||
|
||||
TypedPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: Preference(category, name, parent), _getter(getter), _setter(setter) { }
|
||||
|
||||
T getValue() const { return _getter(); }
|
||||
void setValue(const T& value) { if (_value != value) { _value = value; emitValueChanged(); } }
|
||||
void load() override { _value = _getter(); }
|
||||
void save() const override {
|
||||
T oldValue = _getter();
|
||||
if (_value != oldValue) {
|
||||
_setter(_value);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
T _value;
|
||||
const Getter _getter;
|
||||
const Setter _setter;
|
||||
};
|
||||
|
||||
class BoolPreference : public TypedPreference<bool> {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool value READ getValue WRITE setValue NOTIFY valueChanged)
|
||||
|
||||
public:
|
||||
BoolPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: TypedPreference(category, name, getter, setter, parent) { }
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
protected:
|
||||
void emitValueChanged() override { emit valueChanged(); }
|
||||
};
|
||||
|
||||
class FloatPreference : public TypedPreference<float> {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float value READ getValue WRITE setValue NOTIFY valueChanged)
|
||||
Q_PROPERTY(float min READ getMin CONSTANT)
|
||||
Q_PROPERTY(float max READ getMax CONSTANT)
|
||||
Q_PROPERTY(float step READ getStep CONSTANT)
|
||||
Q_PROPERTY(float decimals READ getDecimals CONSTANT)
|
||||
|
||||
public:
|
||||
FloatPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: TypedPreference(category, name, getter, setter, parent) { }
|
||||
|
||||
float getMin() const { return _min; }
|
||||
void setMin(float min) { _min = min; };
|
||||
|
||||
float getMax() const { return _max; }
|
||||
void setMax(float max) { _max = max; };
|
||||
|
||||
float getStep() const { return _step; }
|
||||
void setStep(float step) { _step = step; };
|
||||
|
||||
float getDecimals() const { return _decimals; }
|
||||
void setDecimals(float decimals) { _decimals = decimals; };
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
protected:
|
||||
void emitValueChanged() override { emit valueChanged(); }
|
||||
|
||||
float _decimals { 0 };
|
||||
float _min { 0 };
|
||||
float _max { 1 };
|
||||
float _step { 0.1f };
|
||||
};
|
||||
|
||||
class StringPreference : public TypedPreference<QString> {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString value READ getValue WRITE setValue NOTIFY valueChanged)
|
||||
|
||||
public:
|
||||
StringPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: TypedPreference(category, name, getter, setter, parent) { }
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
protected:
|
||||
void emitValueChanged() override { emit valueChanged(); }
|
||||
};
|
||||
|
||||
class SliderPreference : public FloatPreference {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SliderPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: FloatPreference(category, name, getter, setter, parent) { }
|
||||
|
||||
Type getType() { return Slider; }
|
||||
};
|
||||
|
||||
class SpinnerPreference : public FloatPreference {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SpinnerPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: FloatPreference(category, name, getter, setter, parent) { }
|
||||
|
||||
Type getType() { return Spinner; }
|
||||
};
|
||||
|
||||
class EditPreference : public StringPreference {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString placeholderText READ getPlaceholderText CONSTANT)
|
||||
|
||||
public:
|
||||
EditPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: StringPreference(category, name, getter, setter, parent) { }
|
||||
Type getType() { return Editable; }
|
||||
const QString& getPlaceholderText() const { return _placeholderText; }
|
||||
void setPlaceholderText(const QString& placeholderText) { _placeholderText = placeholderText; }
|
||||
|
||||
protected:
|
||||
QString _placeholderText;
|
||||
};
|
||||
|
||||
class BrowsePreference : public EditPreference {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString browseLabel READ getBrowseLabel CONSTANT)
|
||||
|
||||
public:
|
||||
BrowsePreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: EditPreference(category, name, getter, setter, parent) { }
|
||||
Type getType() { return Browsable; }
|
||||
|
||||
const QString& getBrowseLabel() { return _browseLabel; }
|
||||
void setBrowseLabel(const QString& browseLabel) { _browseLabel = browseLabel; }
|
||||
|
||||
protected:
|
||||
QString _browseLabel { "Browse" };
|
||||
};
|
||||
|
||||
class CheckPreference : public BoolPreference {
|
||||
Q_OBJECT
|
||||
public:
|
||||
CheckPreference(const QString& category, const QString& name, Getter getter, Setter setter, Preferences* parent = nullptr)
|
||||
: BoolPreference(category, name, getter, setter, parent) { }
|
||||
Type getType() { return Checkbox; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -87,5 +87,13 @@ DISTFILES += \
|
|||
../../interface/resources/qml/menus/VrMenuItem.qml \
|
||||
../../interface/resources/qml/menus/VrMenuView.qml \
|
||||
../../interface/resources/qml/windows/ModalWindow.qml \
|
||||
../../interface/resources/qml/desktop/FocusHack.qml
|
||||
|
||||
../../interface/resources/qml/desktop/FocusHack.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/PreferencesDialog.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/Section.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/Browsable.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/Section.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/Editable.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/Slider.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/Preference.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/SpinBox.qml \
|
||||
../../interface/resources/qml/hifi/dialogs/preferences/CheckBox.qml
|
||||
|
|
|
@ -3,6 +3,36 @@
|
|||
#include <QtWebEngine>
|
||||
#include <QFileSystemModel>
|
||||
|
||||
|
||||
|
||||
class Preference : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString category READ getCategory() CONSTANT)
|
||||
Q_PROPERTY(QString name READ getName() CONSTANT)
|
||||
Q_PROPERTY(Type type READ getType() CONSTANT)
|
||||
Q_ENUMS(Type)
|
||||
public:
|
||||
enum Type {
|
||||
Editable,
|
||||
Browsable,
|
||||
Spinner,
|
||||
Checkbox,
|
||||
};
|
||||
|
||||
Preference(QObject* parent = nullptr) : QObject(parent) {}
|
||||
|
||||
Preference(const QString& category, const QString& name, QObject* parent = nullptr)
|
||||
: QObject(parent), _category(category), _name(name) { }
|
||||
const QString& getCategory() const { return _category; }
|
||||
const QString& getName() const { return _name; }
|
||||
virtual Type getType() { return Editable; }
|
||||
|
||||
protected:
|
||||
const QString _category;
|
||||
const QString _name;
|
||||
};
|
||||
|
||||
|
||||
QString getRelativeDir(const QString& relativePath = ".") {
|
||||
QDir path(__FILE__); path.cdUp();
|
||||
auto result = path.absoluteFilePath(relativePath);
|
||||
|
@ -45,6 +75,7 @@ int main(int argc, char *argv[]) {
|
|||
QDir::setCurrent(getRelativeDir(".."));
|
||||
|
||||
QtWebEngine::initialize();
|
||||
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
addImportPath(engine, "../qml");
|
||||
|
@ -63,3 +94,5 @@ int main(int argc, char *argv[]) {
|
|||
engine.load(QUrl(QStringLiteral("qml/main.qml")));
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
#include "main.moc"
|
||||
|
|
Loading…
Reference in a new issue