mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge branch 'master' of https://github.com/highfidelity/hifi into red
This commit is contained in:
commit
9bfeb4a1d5
19 changed files with 271 additions and 47 deletions
19
interface/resources/config/render.json
Normal file
19
interface/resources/config/render.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"RenderShadowTask": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"RenderDeferredTask": {
|
||||
"AmbientOcclusion": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"Antialiasing": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,7 +49,7 @@ Preference {
|
|||
Button {
|
||||
id: button
|
||||
anchors { right: parent.right; verticalCenter: dataTextField.verticalCenter }
|
||||
text: "Browse"
|
||||
text: preference.browseLabel
|
||||
onClicked: {
|
||||
var browser = fileBrowserBuilder.createObject(desktop, { selectDirectory: true, folder: fileDialogHelper.pathToUrl(preference.value) });
|
||||
browser.selectedFile.connect(function(fileUrl){
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
|
||||
Preference {
|
||||
id: root
|
||||
property real spacing: 8
|
||||
height: labelText.height + dataComboBox.height + spacing
|
||||
|
||||
Component.onCompleted: {
|
||||
dataComboBox.currentIndex = dataComboBox.find(preference.value);
|
||||
}
|
||||
|
||||
function save() {
|
||||
preference.value = dataComboBox.currentText;
|
||||
preference.save();
|
||||
}
|
||||
|
||||
Text {
|
||||
id: labelText
|
||||
color: enabled ? "black" : "gray"
|
||||
text: root.label
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: dataComboBox
|
||||
model: preference.items
|
||||
style: ComboBoxStyle { renderType: Text.QtRendering }
|
||||
anchors {
|
||||
top: labelText.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
topMargin: root.spacing
|
||||
rightMargin: root.spacing
|
||||
}
|
||||
}
|
||||
}
|
|
@ -81,6 +81,7 @@ Preference {
|
|||
property var sliderBuilder: Component { SliderPreference { } }
|
||||
property var avatarBuilder: Component { AvatarPreference { } }
|
||||
property var buttonBuilder: Component { ButtonPreference { } }
|
||||
property var comboBoxBuilder: Component { ComboBoxPreference { } }
|
||||
property var preferences: []
|
||||
|
||||
function buildPreferences() {
|
||||
|
@ -123,7 +124,11 @@ Preference {
|
|||
|
||||
case Preference.Button:
|
||||
builder = buttonBuilder;
|
||||
break
|
||||
break;
|
||||
|
||||
case Preference.ComboBox:
|
||||
builder = comboBoxBuilder;
|
||||
break;
|
||||
};
|
||||
|
||||
if (builder) {
|
||||
|
|
|
@ -7,7 +7,7 @@ PreferencesDialog {
|
|||
id: root
|
||||
objectName: "GeneralPreferencesDialog"
|
||||
title: "General Preferences"
|
||||
showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Graphics"]
|
||||
showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"]
|
||||
property var settings: Settings {
|
||||
category: root.objectName
|
||||
property alias x: root.x
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import QtQuick 2.5
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../dialogs"
|
||||
|
||||
PreferencesDialog {
|
||||
id: root
|
||||
objectName: "GraphicsPreferencesDialog"
|
||||
title: "Graphics Preferences"
|
||||
showCategories: ["Graphics"]
|
||||
property var settings: Settings {
|
||||
category: root.objectName
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
property alias width: root.width
|
||||
property alias height: root.height
|
||||
}
|
||||
}
|
||||
|
|
@ -1156,6 +1156,7 @@ void Application::initializeGL() {
|
|||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||
_renderEngine->addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", cullFunctor);
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
// TODO: Load a cached config file
|
||||
|
||||
|
|
|
@ -312,6 +312,12 @@ Menu::Menu() {
|
|||
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/AudioPreferencesDialog.qml"), "AudioPreferencesDialog");
|
||||
});
|
||||
|
||||
// Settings > Graphics...
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Graphics...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
DependencyManager::get<OffscreenUi>()->toggle(QString("hifi/dialogs/GraphicsPreferencesDialog.qml"), "GraphicsPreferencesDialog");
|
||||
});
|
||||
|
||||
// Settings > LOD...-- FIXME: needs implementation
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "LOD...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
|
|
|
@ -336,24 +336,31 @@ void setupPreferences() {
|
|||
{
|
||||
static const QString RENDER("Graphics");
|
||||
auto renderConfig = qApp->getRenderEngine()->getConfiguration();
|
||||
|
||||
auto ambientOcclusionConfig = renderConfig->getConfig<AmbientOcclusionEffect>();
|
||||
{
|
||||
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<AmbientOcclusionEffect>(); };
|
||||
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<AmbientOcclusionEffect>(enable); };
|
||||
auto preference = new CheckPreference(RENDER, "Ambient Occlusion", getter, setter);
|
||||
auto getter = [ambientOcclusionConfig]()->QString { return ambientOcclusionConfig->getPreset(); };
|
||||
auto setter = [ambientOcclusionConfig](QString preset) { ambientOcclusionConfig->setPreset(preset); };
|
||||
auto preference = new ComboBoxPreference(RENDER, "Ambient Occlusion", getter, setter);
|
||||
preference->setItems(ambientOcclusionConfig->getPresetList());
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
auto antialiasingConfig = renderConfig->getConfig<Antialiasing>();
|
||||
{
|
||||
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<Antialiasing>(); };
|
||||
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<Antialiasing>(enable); };
|
||||
auto preference = new CheckPreference(RENDER, "Antialiasing", getter, setter);
|
||||
auto getter = [antialiasingConfig]()->QString { return antialiasingConfig->getPreset(); };
|
||||
auto setter = [antialiasingConfig](QString preset) { antialiasingConfig->setPreset(preset); };
|
||||
auto preference = new ComboBoxPreference(RENDER, "Antialiasing", getter, setter);
|
||||
preference->setItems(antialiasingConfig->getPresetList());
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
auto shadowConfig = renderConfig->getConfig<RenderShadowTask>();
|
||||
{
|
||||
auto getter = [renderConfig]()->bool { return renderConfig->isJobEnabled<RenderShadowTask>(); };
|
||||
auto setter = [renderConfig](bool enable) { renderConfig->setJobEnabled<RenderShadowTask>(enable); };
|
||||
auto preference = new CheckPreference(RENDER, "Shadows", getter, setter);
|
||||
auto getter = [shadowConfig]()->QString { return shadowConfig->getPreset(); };
|
||||
auto setter = [shadowConfig](QString preset) { shadowConfig->setPreset(preset); };
|
||||
auto preference = new ComboBoxPreference(RENDER, "Shadows", getter, setter);
|
||||
preference->setItems(shadowConfig->getPresetList());
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,26 +16,25 @@ void OctreeElementBag::deleteAll() {
|
|||
_bagElements = Bag();
|
||||
}
|
||||
|
||||
/// does the bag contain elements?
|
||||
/// if all of the contained elements are expired, they will not report as empty, and
|
||||
/// a single last item will be returned by extract as a null pointer
|
||||
bool OctreeElementBag::isEmpty() {
|
||||
// Pop all expired front elements
|
||||
while (!_bagElements.empty() && _bagElements.front().expired()) {
|
||||
_bagElements.pop();
|
||||
}
|
||||
|
||||
return _bagElements.empty();
|
||||
}
|
||||
|
||||
void OctreeElementBag::insert(OctreeElementPointer element) {
|
||||
_bagElements.push(element);
|
||||
_bagElements[element.get()] = element;
|
||||
}
|
||||
|
||||
OctreeElementPointer OctreeElementBag::extract() {
|
||||
OctreeElementPointer result;
|
||||
|
||||
// Find the first element still alive
|
||||
while (!result && !_bagElements.empty()) {
|
||||
result = _bagElements.front().lock(); // Grab head's shared_ptr
|
||||
_bagElements.pop();
|
||||
Bag::iterator it = _bagElements.begin();
|
||||
while (it != _bagElements.end() && !result) {
|
||||
result = it->second.lock();
|
||||
it = _bagElements.erase(it);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,22 @@
|
|||
#ifndef hifi_OctreeElementBag_h
|
||||
#define hifi_OctreeElementBag_h
|
||||
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "OctreeElement.h"
|
||||
|
||||
class OctreeElementBag {
|
||||
using Bag = std::queue<OctreeElementWeakPointer>;
|
||||
using Bag = std::unordered_map<OctreeElement*, OctreeElementWeakPointer>;
|
||||
|
||||
public:
|
||||
void insert(OctreeElementPointer element); // put a element into the bag
|
||||
OctreeElementPointer extract(); // pull a element out of the bag (could come in any order)
|
||||
bool isEmpty();
|
||||
|
||||
OctreeElementPointer extract(); /// pull a element out of the bag (could come in any order) and if all of the
|
||||
/// elements have expired, a single null pointer will be returned
|
||||
|
||||
bool isEmpty(); /// does the bag contain elements,
|
||||
/// if all of the contained elements are expired, they will not report as empty, and
|
||||
/// a single last item will be returned by extract as a null pointer
|
||||
|
||||
void deleteAll();
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "render/DrawTask.h"
|
||||
|
||||
class AmbientOcclusionEffectConfig : public render::Job::Config {
|
||||
class AmbientOcclusionEffectConfig : public render::Job::Config::Persistent {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||
Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty)
|
||||
|
@ -32,7 +32,7 @@ class AmbientOcclusionEffectConfig : public render::Job::Config {
|
|||
Q_PROPERTY(int blurRadius MEMBER blurRadius WRITE setBlurRadius)
|
||||
Q_PROPERTY(double gpuTime READ getGpuTime)
|
||||
public:
|
||||
AmbientOcclusionEffectConfig() : render::Job::Config(false) {}
|
||||
AmbientOcclusionEffectConfig() : render::Job::Config::Persistent("Ambient Occlusion", false) {}
|
||||
|
||||
const int MAX_RESOLUTION_LEVEL = 4;
|
||||
const int MAX_BLUR_RADIUS = 6;
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
#include "render/DrawTask.h"
|
||||
|
||||
class AntiAliasingConfig : public render::Job::Config {
|
||||
class AntiAliasingConfig : public render::Job::Config::Persistent {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled)
|
||||
public:
|
||||
AntiAliasingConfig() : render::Job::Config(false) {}
|
||||
AntiAliasingConfig() : render::Job::Config::Persistent("Antialiasing", false) {}
|
||||
};
|
||||
|
||||
class Antialiasing {
|
||||
|
|
|
@ -31,11 +31,11 @@ protected:
|
|||
render::ShapePlumberPointer _shapePlumber;
|
||||
};
|
||||
|
||||
class RenderShadowTaskConfig : public render::Task::Config {
|
||||
class RenderShadowTaskConfig : public render::Task::Config::Persistent {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool enabled MEMBER enabled NOTIFY dirty)
|
||||
public:
|
||||
RenderShadowTaskConfig() : render::Task::Config(false) {}
|
||||
RenderShadowTaskConfig() : render::Task::Config::Persistent("Shadows", false) {}
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
|
|
|
@ -9,9 +9,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
|
@ -20,6 +25,31 @@ Engine::Engine() :
|
|||
_renderContext(std::make_shared<RenderContext>()) {
|
||||
}
|
||||
|
||||
void Engine::load() {
|
||||
auto config = getConfiguration();
|
||||
const QString configFile= "config/render.json";
|
||||
|
||||
QUrl path(PathUtils::resourcesPath() + configFile);
|
||||
QFile file(path.toString());
|
||||
if (!file.exists()) {
|
||||
qWarning() << "Engine configuration file" << path << "does not exist";
|
||||
} else if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning() << "Engine configuration file" << path << "cannot be opened";
|
||||
} else {
|
||||
QString data = file.readAll();
|
||||
file.close();
|
||||
QJsonParseError error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data.toUtf8(), &error);
|
||||
if (error.error == error.NoError) {
|
||||
config->setPresetList(doc.object());
|
||||
qDebug() << "Engine configuration file" << path << "loaded";
|
||||
} else {
|
||||
qWarning() << "Engine configuration file" << path << "failed to load:" <<
|
||||
error.errorString() << "at offset" << error.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::run() {
|
||||
// Sync GPU state before beginning to render
|
||||
_renderContext->args->_context->syncCache();
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_render_Engine_h
|
||||
#define hifi_render_Engine_h
|
||||
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "Context.h"
|
||||
#include "Task.h"
|
||||
|
||||
|
@ -25,6 +27,10 @@ public:
|
|||
Engine();
|
||||
~Engine() = default;
|
||||
|
||||
// Load any persisted settings, and set up the presets
|
||||
// This should be run after adding all jobs, and before building ui
|
||||
void load();
|
||||
|
||||
// Register the scene
|
||||
void registerScene(const ScenePointer& scene) { _sceneContext->_scene = scene; }
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <QtCore/qjsonvalue.h>
|
||||
#include <shared/JSONHelpers.h>
|
||||
|
||||
#include "SettingHandle.h"
|
||||
|
||||
#include "Context.h"
|
||||
|
||||
#include "gpu/Batch.h"
|
||||
|
@ -59,10 +61,75 @@ class Job;
|
|||
class Task;
|
||||
class JobNoIO {};
|
||||
|
||||
template <class C> class PersistentConfig : public C {
|
||||
public:
|
||||
const QString DEFAULT = "Default";
|
||||
const QString NONE = "None";
|
||||
|
||||
PersistentConfig() = delete;
|
||||
PersistentConfig(const QString& path) :
|
||||
_preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { }
|
||||
PersistentConfig(const QStringList& path) :
|
||||
_preset(QStringList() << "Render" << "Engine" << path, DEFAULT) { }
|
||||
PersistentConfig(const QString& path, bool enabled) : C(enabled),
|
||||
_preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { }
|
||||
PersistentConfig(const QStringList& path, bool enabled) : C(enabled),
|
||||
_preset(QStringList() << "Render" << "Engine" << path, enabled ? DEFAULT : NONE) { }
|
||||
|
||||
QStringList getPresetList() {
|
||||
if (_presets.empty()) {
|
||||
setPresetList(QJsonObject());
|
||||
}
|
||||
return _presets.keys();
|
||||
}
|
||||
|
||||
virtual void setPresetList(const QJsonObject& list) override {
|
||||
assert(_presets.empty());
|
||||
|
||||
_default = toJsonValue(*this).toObject().toVariantMap();
|
||||
|
||||
_presets.unite(list.toVariantMap());
|
||||
if (C::alwaysEnabled || C::enabled) {
|
||||
_presets.insert(DEFAULT, _default);
|
||||
}
|
||||
if (!C::alwaysEnabled) {
|
||||
_presets.insert(NONE, QVariantMap{{ "enabled", false }});
|
||||
}
|
||||
|
||||
auto preset = _preset.get();
|
||||
if (preset != _preset.getDefault() && _presets.contains(preset)) {
|
||||
// Load the persisted configuration
|
||||
C::load(_presets[preset].toMap());
|
||||
}
|
||||
}
|
||||
|
||||
QString getPreset() { return _preset.get(); }
|
||||
|
||||
void setPreset(const QString& preset) {
|
||||
_preset.set(preset);
|
||||
if (_presets.contains(preset)) {
|
||||
// Always start back at default to remain deterministic
|
||||
QVariantMap config = _default;
|
||||
QVariantMap presetConfig = _presets[preset].toMap();
|
||||
for (auto it = presetConfig.cbegin(); it != presetConfig.cend(); it++) {
|
||||
config.insert(it.key(), it.value());
|
||||
}
|
||||
C::load(config);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
QVariantMap _default;
|
||||
QVariantMap _presets;
|
||||
Setting::Handle<QString> _preset;
|
||||
};
|
||||
|
||||
// A default Config is always on; to create an enableable Config, use the ctor JobConfig(bool enabled)
|
||||
class JobConfig : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using Persistent = PersistentConfig<JobConfig>;
|
||||
|
||||
JobConfig() = default;
|
||||
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
|
||||
|
||||
|
@ -71,17 +138,31 @@ public:
|
|||
bool alwaysEnabled{ true };
|
||||
bool enabled{ true };
|
||||
|
||||
virtual void setPresetList(const QJsonObject& object) {
|
||||
for (auto it = object.begin(); it != object.end(); it++) {
|
||||
JobConfig* child = findChild<JobConfig*>(it.key(), Qt::FindDirectChildrenOnly);
|
||||
if (child) {
|
||||
child->setPresetList(it.value().toObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This must be named toJSON to integrate with the global scripting JSON object
|
||||
Q_INVOKABLE QString toJSON() { return QJsonDocument(toJsonValue(*this).toObject()).toJson(QJsonDocument::Compact); }
|
||||
Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); }
|
||||
Q_INVOKABLE void load(const QVariantMap& map) { qObjectFromJsonValue(QJsonObject::fromVariantMap(map), *this); emit loaded(); }
|
||||
|
||||
public slots:
|
||||
void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); }
|
||||
void load(const QJsonObject& val) { qObjectFromJsonValue(val, *this); emit loaded(); }
|
||||
|
||||
signals:
|
||||
void loaded();
|
||||
};
|
||||
|
||||
class TaskConfig : public JobConfig {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using Persistent = PersistentConfig<TaskConfig>;
|
||||
|
||||
TaskConfig() = default ;
|
||||
TaskConfig(bool enabled) : JobConfig(enabled) {}
|
||||
|
||||
|
@ -95,15 +176,6 @@ public:
|
|||
return findChild<typename T::Config*>(name);
|
||||
}
|
||||
|
||||
template <class T> void setJobEnabled(bool enable = true, std::string job = "") {
|
||||
assert(getConfig<T>(job)->alwaysEnabled != true);
|
||||
getConfig<T>(job)->enabled = enable;
|
||||
refresh(); // trigger a Job->configure
|
||||
}
|
||||
template <class T> bool isJobEnabled(bool enable = true, std::string job = "") const {
|
||||
return getConfig<T>(job)->isEnabled();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void refresh();
|
||||
|
||||
|
@ -236,8 +308,7 @@ public:
|
|||
const Varying getInput() const { return _input; }
|
||||
const Varying getOutput() const { return _output; }
|
||||
|
||||
Model(const Varying& input, Data data = Data()) : Concept(std::make_shared<C>()), _data(data), _input(input), _output(Output()) {
|
||||
_config = _data._config; // use the data's config
|
||||
Model(const Varying& input, Data data = Data()) : Concept(data._config), _data(data), _input(input), _output(Output()) {
|
||||
std::static_pointer_cast<Config>(_config)->init(&_data);
|
||||
applyConfiguration();
|
||||
}
|
||||
|
@ -273,9 +344,11 @@ public:
|
|||
config->setParent(_config.get());
|
||||
config->setObjectName(name.c_str());
|
||||
|
||||
// Connect dirty->refresh if defined
|
||||
// Connect loaded->refresh
|
||||
QObject::connect(config.get(), SIGNAL(loaded()), _config.get(), SLOT(refresh()));
|
||||
static const char* DIRTY_SIGNAL = "dirty()";
|
||||
if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
||||
// Connect dirty->refresh if defined
|
||||
QObject::connect(config.get(), SIGNAL(dirty()), _config.get(), SLOT(refresh()));
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
Spinner,
|
||||
Checkbox,
|
||||
Button,
|
||||
ComboBox,
|
||||
// Special casing for an unusual preference
|
||||
Avatar
|
||||
};
|
||||
|
@ -236,6 +237,22 @@ protected:
|
|||
QString _placeholderText;
|
||||
};
|
||||
|
||||
class ComboBoxPreference : public EditPreference {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QStringList items READ getItems CONSTANT)
|
||||
|
||||
public:
|
||||
ComboBoxPreference(const QString& category, const QString& name, Getter getter, Setter setter)
|
||||
: EditPreference(category, name, getter, setter) { }
|
||||
Type getType() { return ComboBox; }
|
||||
|
||||
const QStringList& getItems() { return _items; }
|
||||
void setItems(const QStringList& items) { _items = items; }
|
||||
|
||||
protected:
|
||||
QStringList _items;
|
||||
};
|
||||
|
||||
class BrowsePreference : public EditPreference {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString browseLabel READ getBrowseLabel CONSTANT)
|
||||
|
|
|
@ -111,7 +111,7 @@ void qObjectFromJsonValue(const QJsonValue& j, QObject& o) {
|
|||
for (auto it = object.begin(); it != object.end(); it++) {
|
||||
std::string key = it.key().toStdString();
|
||||
if (it.value().isObject()) {
|
||||
QObject* child = o.findChild<QObject*>(key.c_str(), Qt::FindChildOption::FindDirectChildrenOnly);
|
||||
QObject* child = o.findChild<QObject*>(key.c_str(), Qt::FindDirectChildrenOnly);
|
||||
if (child) {
|
||||
qObjectFromJsonValue(it.value(), *child);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue