summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Janes <mark.a.janes@intel.com>2017-11-26 07:26:56 -0800
committerMark Janes <mark.a.janes@intel.com>2017-11-27 14:41:46 -0800
commite62b5987eb8ace7c7a74d3e0badb0215a26f105e (patch)
treed0b8478c73a0e78434654680bc468d395e04d40e
parent63c528de8b0bdbc8322c07edf4e5c5f3ecd8fb0f (diff)
State: Refactor state display
Initial implementation used ad-hoc hints to correctly display various types of data. With this commit, a generic implementation incorporates the "indices" into the data model, so all state can be displayed as a vector of items. The state table is not re-created on each selection, which maintains the state of the triangle widget for collapsing directories.
-rw-r--r--retrace/daemon/glframe_state_enums.cpp12
-rw-r--r--retrace/daemon/glframe_state_enums.hpp1
-rw-r--r--retrace/daemon/glframe_state_override.cpp56
-rw-r--r--retrace/daemon/ui/glframe_state_model.cpp186
-rw-r--r--retrace/daemon/ui/glframe_state_model.hpp40
-rw-r--r--retrace/daemon/ui/qml/StateControl.qml148
6 files changed, 168 insertions, 275 deletions
diff --git a/retrace/daemon/glframe_state_enums.cpp b/retrace/daemon/glframe_state_enums.cpp
index f7295062..329291e0 100644
--- a/retrace/daemon/glframe_state_enums.cpp
+++ b/retrace/daemon/glframe_state_enums.cpp
@@ -207,3 +207,15 @@ glretrace::state_name_to_choices(const std::string &n) {
}
}
+std::vector<std::string>
+glretrace::state_name_to_indices(const std::string &n) {
+ switch (state_name_to_enum(n)) {
+ case GL_COLOR_WRITEMASK:
+ return {"Red Enabled", "Green Enabled", "Blue Enabled", "Alpha Enabled"};
+ case GL_BLEND_COLOR:
+ case GL_COLOR_CLEAR_VALUE:
+ return {"Red", "Green", "Blue", "Alpha"};
+ default:
+ return {};
+ }
+}
diff --git a/retrace/daemon/glframe_state_enums.hpp b/retrace/daemon/glframe_state_enums.hpp
index daeee8de..95302187 100644
--- a/retrace/daemon/glframe_state_enums.hpp
+++ b/retrace/daemon/glframe_state_enums.hpp
@@ -39,6 +39,7 @@ namespace glretrace {
uint32_t state_name_to_enum(const std::string &value);
std::string state_enum_to_name(GLint value);
std::vector<std::string> state_name_to_choices(const std::string &n);
+std::vector<std::string> state_name_to_indices(const std::string &n);
} // namespace glretrace
diff --git a/retrace/daemon/glframe_state_override.cpp b/retrace/daemon/glframe_state_override.cpp
index 7459200a..a4a807d4 100644
--- a/retrace/daemon/glframe_state_override.cpp
+++ b/retrace/daemon/glframe_state_override.cpp
@@ -67,14 +67,9 @@ StateOverride::setState(const StateKey &item,
// model.
void
StateOverride::adjust_item(StateKey *item) const {
- switch (state_name_to_enum(item->name)) {
- case GL_COLOR_WRITEMASK: {
- item->path = "";
- break;
- }
- default:
- break;
- }
+ // initially required by GL_COLOR_WRITEMASK, which can now be
+ // implemented within the generic pattern.
+ return;
}
// As with adjust_item, offsets from the UI do not always match the
@@ -83,22 +78,9 @@ StateOverride::adjust_item(StateKey *item) const {
void
StateOverride::adjust_offset(const StateKey &item,
int *offset) const {
- switch (state_name_to_enum(item.name)) {
- case GL_COLOR_WRITEMASK: {
- static const std::map<std::string, int> writemask_offsets {
- { "FrameBuffer State/Red Enabled", 0 },
- { "FrameBuffer State/Green Enabled", 1 },
- { "FrameBuffer State/Blue Enabled", 2 },
- { "FrameBuffer State/Alpha Enabled", 3 },
- };
- const auto i = writemask_offsets.find(item.path);
- assert(i != writemask_offsets.end());
- *offset = i->second;
- return;
- }
- default:
- return;
- }
+ // initially required by GL_COLOR_WRITEMASK, which can now be
+ // implemented within the generic pattern.
+ return;
}
// The UI uses strings for all state values. The override model
@@ -479,29 +461,13 @@ StateOverride::onState(SelectionId selId,
callback->onState(selId, experimentCount, renderId, k, color);
}
{
- StateKey k("FrameBuffer State/Red Enabled",
- "GL_COLOR_WRITEMASK");
+ StateKey k("FrameBuffer State", "GL_COLOR_WRITEMASK");
getState(k, &data);
callback->onState(selId, experimentCount, renderId, k,
- {data[0] ? "true" : "false"});
- {
- StateKey k("FrameBuffer State/Green Enabled",
- "GL_COLOR_WRITEMASK");
- callback->onState(selId, experimentCount, renderId, k,
- {data[1] ? "true" : "false"});
- }
- {
- StateKey k("FrameBuffer State/Blue Enabled",
- "GL_COLOR_WRITEMASK");
- callback->onState(selId, experimentCount, renderId, k,
- {data[2] ? "true" : "false"});
- }
- {
- StateKey k("FrameBuffer State/Alpha Enabled",
- "GL_COLOR_WRITEMASK");
- callback->onState(selId, experimentCount, renderId, k,
- {data[3] ? "true" : "false"});
- }
+ {data[0] ? "true" : "false",
+ data[1] ? "true" : "false",
+ data[2] ? "true" : "false",
+ data[3] ? "true" : "false"});
}
{
StateKey k("Depth State", "GL_DEPTH_CLEAR_VALUE");
diff --git a/retrace/daemon/ui/glframe_state_model.cpp b/retrace/daemon/ui/glframe_state_model.cpp
index cdc7d496..c028c908 100644
--- a/retrace/daemon/ui/glframe_state_model.cpp
+++ b/retrace/daemon/ui/glframe_state_model.cpp
@@ -51,18 +51,19 @@ QStateValue::QStateValue(QObject *parent) {
QStateValue::QStateValue(QObject *parent,
const std::string &_path,
const std::string &_name,
- const std::vector<std::string> &_choices)
+ const std::vector<std::string> &_choices,
+ const std::vector<std::string> &_indices)
: m_path(_path.c_str()),
m_name(_name.c_str()),
- m_value(kUninitializedValue),
- m_visible(true),
- m_type(QStateValue::KglDirectory) {
+ m_value({}),
+ m_visible(true) {
moveToThread(parent->thread());
- if (!_choices.empty())
- m_type = QStateValue::KglEnum;
for (auto c : _choices)
- m_choices.append(QVariant(c.c_str()));
+ m_choices.append(QString(c.c_str()));
+ for (auto i : _indices)
+ m_indices.append(QString(i.c_str()));
+
const int path_count = std::count(_path.begin(), _path.end(), '/');
const int indent = path_count + (_name.length() > 0 ? 1 : 0);
m_indent = indent;
@@ -71,75 +72,44 @@ QStateValue::QStateValue(QObject *parent,
}
void
-QStateValue::insert(const std::string &value) {
- int value_index = 0;
- QVariant qvalue(value.c_str());
- if (m_type == QStateValue::KglEnum) {
- for (auto c : m_choices) {
- if (qvalue == c)
- break;
- ++value_index;
- }
- // value must be found
- assert(value_index < m_choices.size());
- if (m_value == kUninitializedValue) {
- // first render, display the value
- m_value = value_index;
- return;
- }
-
- if (m_value != value_index)
- // selected renders have different values
- m_value = kMixedValue;
-
- return;
+QStateValue::insert(const std::vector<std::string> &value) {
+ QStringList new_value;
+ for (auto i : value) {
+ new_value.append(m_choices.length() ?
+ value_to_choice(i) :
+ QString::fromStdString(i));
}
- // else
- m_type = QStateValue::KglFloat;
- const QString new_val = QString::fromStdString(value);
- if (m_value == kUninitializedValue) {
- m_value = new_val;
+ if (m_value.length() == 0) {
+ m_value = new_value;
+ emit valueChanged();
return;
}
- if (m_value != new_val)
- m_value = "###";
-}
-void
-QStateValue::insert(const std::string &red,
- const std::string &blue,
- const std::string &green,
- const std::string &alpha) {
- m_type = QStateValue::KglColor;
- QStringList color;
- color.append(QString::fromStdString(red));
- color.append(QString::fromStdString(blue));
- color.append(QString::fromStdString(green));
- color.append(QString::fromStdString(alpha));
-
- if (m_value == kUninitializedValue) {
- // selected renders have different values
- m_value = color;
+ // else we are appending values from a multiple-render selection to
+ // an existing value.
+ if (m_value == new_value)
return;
- }
- if (m_value != color) {
- // selected renders have different values
- QStringList tmp = m_value.value<QStringList>();
- for (int i = 0; i < 4; ++i) {
- if (tmp[i] != color[i])
- tmp[i] = "###";
- }
- m_value = tmp;
+ QStringList tmp = m_value;
+ for (int i = 0; i < tmp.size(); ++i) {
+ if (tmp[i] != new_value[i])
+ tmp[i] = "###";
}
+ m_value = tmp;
+ emit valueChanged();
}
QStateModel::QStateModel() {}
QStateModel::QStateModel(IFrameRetrace *retrace) : m_retrace(retrace) {}
-QStateModel::~QStateModel() {}
+QStateModel::~QStateModel() {
+ for (auto i : m_states)
+ delete i;
+ m_states.clear();
+ m_state_by_name.clear();
+}
QQmlListProperty<QStateValue> QStateModel::state() {
ScopedLock s(m_protect);
@@ -148,27 +118,10 @@ QQmlListProperty<QStateValue> QStateModel::state() {
void
QStateModel::clear() {
- // QObjects being displayed in the UI must be cleared from the UI
- // before being deleted. This routine is invoked in the UI thread
- // (as opposed to the retrace thread). The emit with the empty
- // states calls down into ::state() to retrieve the new empty list
- // within a single thread. After emit, it is safe to delete the
- // objects. Conversely, if these objects were cleaned up after an
- // emit in the retrace thread, the request for updated state would
- // be enqueued. The result is an asynchronous crash.
- {
- ScopedLock s(m_protect);
- m_states.clear();
- }
- emit stateChanged();
{
ScopedLock s(m_protect);
- m_state_by_name.clear();
- m_renders.clear();
- m_known_paths.clear();
- for (auto i : m_for_deletion)
- delete i;
- m_for_deletion.clear();
+ for (auto i : m_states)
+ i->clear();
}
}
@@ -178,13 +131,16 @@ void QStateModel::onState(SelectionId selectionCount,
StateKey item,
const std::vector<std::string> &value) {
if (selectionCount == SelectionId(SelectionId::INVALID_SELECTION)) {
- refresh();
return;
}
if ((selectionCount > m_sel_count) ||
- (experimentCount > m_experiment_count))
+ (experimentCount > m_experiment_count)) {
+ // state values for a new selection/experiment. Discard existing
+ // values.
clear();
+ m_renders.clear();
+ }
ScopedLock s(m_protect);
if ((selectionCount > m_sel_count) ||
@@ -197,6 +153,16 @@ void QStateModel::onState(SelectionId selectionCount,
}
if (m_renders.empty() || renderId != m_renders.back())
m_renders.push_back(renderId);
+
+ auto state_value = m_state_by_name.find(item);
+ if (state_value != m_state_by_name.end()) {
+ // update existing value
+ state_value->second->insert(value);
+ return;
+ }
+
+ // else this is a state value that has not been seen before. Create
+ // QStateValue objects for the directory tree and the value itself.
std::string path_comp = item.path;
while (path_comp.length() > 0) {
auto known = m_known_paths.find(path_comp);
@@ -205,7 +171,7 @@ void QStateModel::onState(SelectionId selectionCount,
QStateValue *i = new QStateValue(this,
path_comp,
"",
- {});
+ {}, {});
StateKey k(path_comp, "");
m_state_by_name[k] = i;
m_known_paths[path_comp] = true;
@@ -216,26 +182,21 @@ void QStateModel::onState(SelectionId selectionCount,
}
auto &name = item.name;
- auto state_value = m_state_by_name.find(item);
- if (state_value == m_state_by_name.end()) {
- QStateValue *i = new QStateValue(this,
- item.path,
- name,
- state_name_to_choices(name));
- m_state_by_name[item] = i;
- state_value = m_state_by_name.find(item);
- m_for_deletion.push_back(i);
- }
- if (value.size() == 1) {
- state_value->second->insert(value[0]);
- return;
- }
- if (value.size() == 4) {
- // color value
- state_value->second->insert(value[0], value[1], value[2], value[3]);
- return;
- }
- assert(false);
+ QStateValue *i = new QStateValue(this,
+ item.path,
+ name,
+ state_name_to_choices(name),
+ state_name_to_indices(name));
+ m_state_by_name[item] = i;
+ state_value = m_state_by_name.find(item);
+ i->insert(value);
+
+ // the list of QStateValue objects has changed, resort and redraw
+ // the ListView displaying them.
+ m_states.clear();
+ for (auto i : m_state_by_name)
+ m_states.push_back(i.second);
+ emit stateChanged();
}
void
@@ -255,8 +216,7 @@ QStateModel::setState(const QString &path,
sel.series.push_back(RenderSequence(*r, RenderId(r->index() + 1)));
++r;
}
-
- StateKey key(path.toStdString(), name.toStdString());
+ const StateKey key(path.toStdString(), name.toStdString());
m_retrace->setState(sel, key, offset, value.toStdString());
emit stateExperiment();
}
@@ -349,3 +309,17 @@ QStateModel::search(const QString &_search) {
m_search = _search;
set_visible();
}
+
+QString
+QStateValue::value_to_choice(const std::string &_value) {
+ assert(m_choices.length() > 0);
+ int c = 0;
+ const QString v(_value.c_str());
+ for (const auto &i : m_choices) {
+ if (i == v)
+ return QString().setNum(c);
+ ++c;
+ }
+ assert(false);
+ return QString();
+}
diff --git a/retrace/daemon/ui/glframe_state_model.hpp b/retrace/daemon/ui/glframe_state_model.hpp
index deb3a7b9..56819b2b 100644
--- a/retrace/daemon/ui/glframe_state_model.hpp
+++ b/retrace/daemon/ui/glframe_state_model.hpp
@@ -49,50 +49,46 @@ class QStateValue : public QObject, NoCopy, NoAssign, NoMove {
Q_PROPERTY(QString path READ path CONSTANT)
Q_PROPERTY(QString name READ name CONSTANT)
- Q_PROPERTY(QVariant value READ value CONSTANT)
+ Q_PROPERTY(QStringList value READ value NOTIFY valueChanged)
Q_PROPERTY(QVariant indent READ indent CONSTANT)
- Q_PROPERTY(QStateType valueType READ valueType CONSTANT)
Q_PROPERTY(QVariant visible
READ visible
WRITE setVisible
NOTIFY visibleChanged)
- Q_PROPERTY(QList<QVariant> choices READ choices CONSTANT)
+ Q_PROPERTY(QStringList choices READ choices CONSTANT)
+ Q_PROPERTY(QStringList indices READ indices CONSTANT)
public:
- enum QStateType {
- KglDirectory,
- KglEnum,
- KglFloat,
- KglColor
- };
- Q_ENUMS(QStateType);
-
explicit QStateValue(QObject *parent = 0);
QStateValue(QObject *parent,
const std::string &_path,
const std::string &_name,
- const std::vector<std::string> &_choices);
- void insert(const std::string &value);
- void insert(const std::string &red, const std::string &blue,
- const std::string &green, const std::string &alpha);
+ const std::vector<std::string> &_choices,
+ const std::vector<std::string> &_indices);
+ void insert(const std::vector<std::string> &value);
QString path() const { return m_path; }
QString name() const { return m_name; }
- QStateType valueType() const { return m_type; }
- QVariant value() const { return m_value; }
+ QStringList value() const { return m_value; }
QVariant indent() const { return m_indent; }
QVariant visible() const { return m_visible; }
void setVisible(QVariant v) { m_visible = v; emit visibleChanged(); }
- QList<QVariant> choices() const { return m_choices; }
+ QStringList choices() const { return m_choices; }
+ QStringList indices() const { return m_indices; }
+ void clear() { m_value.clear(); emit valueChanged(); }
signals:
void visibleChanged();
+ void valueChanged();
private:
+ QString value_to_choice(const std::string &_value);
+
QString m_path, m_name;
- QVariant m_value, m_indent, m_visible;
- QStateType m_type;
- QList<QVariant> m_choices;
+ QStringList m_value;
+ QVariant m_indent, m_visible;
+ QStringList m_choices;
+ QStringList m_indices;
};
class QStateModel : public QObject,
@@ -130,12 +126,10 @@ class QStateModel : public QObject,
IFrameRetrace *m_retrace;
SelectionId m_sel_count;
ExperimentId m_experiment_count;
- // typedef QList<QStateValue*> StateList;
std::map<StateKey, QStateValue*> m_state_by_name;
std::map<std::string, bool> m_filter_paths;
std::map<std::string, bool> m_known_paths;
QList<QStateValue*> m_states;
- std::vector<QStateValue*> m_for_deletion;
std::vector<RenderId> m_renders;
QString m_search;
mutable std::mutex m_protect;
diff --git a/retrace/daemon/ui/qml/StateControl.qml b/retrace/daemon/ui/qml/StateControl.qml
index a1a94b02..101cbc22 100644
--- a/retrace/daemon/ui/qml/StateControl.qml
+++ b/retrace/daemon/ui/qml/StateControl.qml
@@ -54,9 +54,10 @@ Item {
model: stateModel.state
anchors.fill: parent
delegate: Component {
+ id: currentDelegate
Row {
visible: modelData.visible
- height: modelData.visible ? combo.height : 0
+ height: modelData.visible ? choices.height : 0
spacing: 10
Rectangle {
id: indent
@@ -70,7 +71,7 @@ Item {
width: nameText.height * 0.75
height: nameText.height * 0.75
source: "qrc:///qml/images/if_next_right_82215.png"
- visible: (modelData.valueType == QStateValue.KglDirectory)
+ visible: (modelData.value.length == 0)
property var collapsed: false
transform: Rotation {
origin.x: collapse.width / 2
@@ -96,113 +97,58 @@ Item {
anchors.verticalCenter: parent.verticalCenter
text: modelData.name + " : "
}
- TextInput {
- anchors.margins: 3
- anchors.verticalCenter: parent.verticalCenter
- visible: (modelData.valueType == QStateValue.KglFloat)
- validator: DoubleValidator{}
- text: (modelData.valueType == QStateValue.KglFloat) ? modelData.value : ""
- Keys.onReturnPressed: {
- if (!acceptableInput) {
- text = modelData.value;
- return;
- }
- stateModel.setState(modelData.path,
- modelData.name,
- 0,
- text);
- }
- }
Row {
- anchors.verticalCenter: parent.verticalCenter
+ id: dataRow
spacing: 10
- visible: (modelData.valueType == QStateValue.KglColor)
- Text{
- text: "Red: "
- }
- TextInput {
- anchors.margins: 3
- validator: DoubleValidator{}
- text: (modelData.valueType == QStateValue.KglColor) ? modelData.value[0] : ""
- Keys.onReturnPressed: {
- if (!acceptableInput) {
- text = modelData.value[0];
- return;
- }
- stateModel.setState(modelData.path,
- modelData.name,
- 0,
- text);
- }
- }
- Text{
- text: "Blue: "
- }
- TextInput {
- anchors.margins: 3
- validator: DoubleValidator{}
- text: (modelData.valueType == QStateValue.KglColor) ? modelData.value[1] : ""
- Keys.onReturnPressed: {
- if (!acceptableInput) {
- text = modelData.value[1];
- return;
+ property var rowModel: currentDelegate.modelData
+ Repeater {
+ model: modelData.value.length;
+ property var indices: modelData.indices
+ property var value: modelData.value
+ property var path: modelData.path
+ property var name: modelData.name
+ property var choices: modelData.choices
+ Row {
+ property var offset: index
+ spacing: 10
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ visible: indices.length > 0
+ text: visible ? indices[offset] : ""
}
- stateModel.setState(modelData.path,
- modelData.name,
- 1,
- text);
- }
- }
- Text{
- text: "Green: "
- }
- TextInput {
- anchors.margins: 3
- validator: DoubleValidator{}
- text: (modelData.valueType == QStateValue.KglColor) ? modelData.value[2] : ""
- Keys.onReturnPressed: {
- if (!acceptableInput) {
- text = modelData.value[2];
- return;
+ TextInput {
+ anchors.margins: 3
+ anchors.verticalCenter: parent.verticalCenter
+ visible: choices.length == 0
+ validator: DoubleValidator{}
+ text: value[offset]
+ Keys.onReturnPressed: {
+ if (!acceptableInput) {
+ text = modelData.value[0];
+ return;
+ }
+ stateModel.setState(path,
+ name,
+ offset,
+ text);
+ }
}
- stateModel.setState(modelData.path,
- modelData.name,
- 2,
- text);
- }
- }
- Text{
- text: "Alpha: "
- }
- TextInput {
- validator: DoubleValidator{}
- anchors.margins: 3
- text: (modelData.valueType == QStateValue.KglColor) ? modelData.value[3] : ""
- Keys.onReturnPressed: {
- if (!acceptableInput) {
- text = modelData.value[3];
- return;
+ ComboBoxFitContents {
+ anchors.verticalCenter: parent.verticalCenter
+ model: choices
+ currentIndex: parseInt(value[offset])
+ visible: choices.length > 0
+ onActivated: {
+ stateModel.setState(path,
+ name,
+ offset,
+ choices[currentIndex]);
+ }
}
- stateModel.setState(modelData.path,
- modelData.name,
- 3,
- text);
+
}
}
}
- ComboBoxFitContents {
- id: combo
- anchors.verticalCenter: parent.verticalCenter
- model: modelData.choices
- currentIndex: (modelData.valueType == QStateValue.KglEnum ? modelData.value : 0)
- visible: (modelData.valueType == QStateValue.KglEnum)
- onActivated: {
- stateModel.setState(modelData.path,
- modelData.name,
- 0,
- modelData.choices[currentIndex]);
- }
- }
}
}
}