Compare commits

...

2 commits

3 changed files with 116 additions and 65 deletions

View file

@ -62,7 +62,7 @@ else()
endif()
target_include_directories(editor PUBLIC "../core/src" "../include")
target_link_libraries(editor PRIVATE openblocks Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::WidgetsPrivate Qt${QT_VERSION_MAJOR}::Multimedia)
target_link_libraries(editor PRIVATE openblocks Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Multimedia)
# Qt6 does not include QOpenGLWidgets as part of Widgets base anymore, so
# we have to include it manually

View file

@ -1,30 +1,16 @@
#include "propertiesview.h"
#include "panes/propertiesview.h"
#include "datatypes/base.h"
#include "datatypes/color3.h"
#include "datatypes/meta.h"
#include "objects/base/member.h"
#include <map>
#include <qabstractitemdelegate.h>
#include <qbrush.h>
#include <qcolordialog.h>
#include <qlineedit.h>
#include <qnamespace.h>
#include <qpalette.h>
#include <qspinbox.h>
#include <qstyle.h>
#include <qstyleditemdelegate.h>
#include <qstyleoption.h>
#include <qtreewidget.h>
#include <QDebug>
#include <QStyledItemDelegate>
#include <private/qtreeview_p.h>
#include <QDoubleSpinBox>
#include <QColorDialog>
class CustomItemDelegate : public QStyledItemDelegate {
#include <QColorDialog>
#include <QLineEdit>
#include <QSpinBox>
#include <QStyledItemDelegate>
#include <QPainter>
class PropertiesItemDelegate : public QStyledItemDelegate {
PropertiesView* view;
public:
CustomItemDelegate(PropertiesView* parent) : view(parent), QStyledItemDelegate(parent) {}
PropertiesItemDelegate(PropertiesView* parent) : view(parent), QStyledItemDelegate(parent) {}
void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const override {
// https://stackoverflow.com/a/76645757/16255372
@ -34,9 +20,7 @@ public:
QStyledItemDelegate::initStyleOption(option, index);
if (index.parent().isValid()) {
option->rect.adjust(-indent, 0, -indent, 0);
} else {
if (!index.parent().isValid()) {
option->state &= ~QStyle::State_Selected;
option->backgroundBrush = view->palette().dark();
@ -48,11 +32,32 @@ public:
if (!index.parent().isValid() || !view->currentInstance || view->currentInstance->expired()) return nullptr;
InstanceRef inst = view->currentInstance->lock();
std::string propertyName = view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString();
// If the property is deeper than 1 layer, then it is considered composite
// Handle specially
bool isComposite = index.parent().parent().isValid();
std::string componentName = isComposite ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString() : "";
std::string propertyName = !isComposite ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString()
: view->itemFromIndex(index.parent())->data(0, Qt::DisplayRole).toString().toStdString();
PropertyMeta meta = inst->GetPropertyMeta(propertyName).value();
Data::Variant currentValue = inst->GetPropertyValue(propertyName).value();
if (isComposite) {
if (meta.type == &Data::Vector3::TYPE) {
Data::Vector3 vector = currentValue.get<Data::Vector3>();
float value = componentName == "X" ? vector.X() : componentName == "Y" ? vector.Y() : componentName == "Z" ? vector.Z() : 0;
QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent);
spinBox->setValue(value);
return spinBox;
}
return nullptr;
}
if (meta.type == &Data::Float::TYPE) {
QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent);
spinBox->setValue(currentValue.get<Data::Float>());
@ -91,19 +96,33 @@ public:
return nullptr;
}
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const override {
editor->setGeometry(option.rect.adjusted(-view->indentation(), 0, -view->indentation(), 0));
}
void setEditorData(QWidget *editor, const QModelIndex &index) const override {
if (index.column() == 0) return;
if (!index.parent().isValid() || !view->currentInstance || view->currentInstance->expired()) return;
InstanceRef inst = view->currentInstance->lock();
std::string propertyName = view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString();
bool isComposite = index.parent().parent().isValid();
std::string componentName = isComposite ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString() : "";
std::string propertyName = !index.parent().parent().isValid() ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString()
: view->itemFromIndex(index.parent())->data(0, Qt::DisplayRole).toString().toStdString();
PropertyMeta meta = inst->GetPropertyMeta(propertyName).value();
Data::Variant currentValue = inst->GetPropertyValue(propertyName).value();
if (isComposite) {
if (meta.type == &Data::Vector3::TYPE) {
Data::Vector3 vector = currentValue.get<Data::Vector3>();
float value = componentName == "X" ? vector.X() : componentName == "Y" ? vector.Y() : componentName == "Z" ? vector.Z() : 0;
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
spinBox->setValue(value);
return;
}
return;
}
if (meta.type == &Data::Float::TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
@ -135,9 +154,31 @@ public:
if (!index.parent().isValid() || !view->currentInstance || view->currentInstance->expired()) return;
InstanceRef inst = view->currentInstance->lock();
std::string propertyName = view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString();
bool isComposite = index.parent().parent().isValid();
std::string componentName = isComposite ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString() : "";
std::string propertyName = !index.parent().parent().isValid() ? view->itemFromIndex(index)->data(0, Qt::DisplayRole).toString().toStdString()
: view->itemFromIndex(index.parent())->data(0, Qt::DisplayRole).toString().toStdString();
PropertyMeta meta = inst->GetPropertyMeta(propertyName).value();
if (isComposite) {
if (meta.type == &Data::Vector3::TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
float value = spinBox->value();
Data::Vector3 prev = inst->GetPropertyValue(propertyName).value().get<Data::Vector3>();
Data::Vector3 newVector = componentName == "X" ? Data::Vector3(value, prev.Y(), prev.Z())
: componentName == "Y" ? Data::Vector3(prev.X(), value, prev.Z())
: componentName == "Z" ? Data::Vector3(prev.X(), prev.Y(), value) : prev;
inst->SetPropertyValue(propertyName, newVector);
view->rebuildCompositeProperty(view->itemFromIndex(index.parent()), &Data::Vector3::TYPE, newVector);
return;
}
return;
}
if (meta.type == &Data::Float::TYPE) {
QDoubleSpinBox* spinBox = dynamic_cast<QDoubleSpinBox*>(editor);
@ -168,6 +209,7 @@ public:
if (!parsedResult) return;
inst->SetPropertyValue(propertyName, parsedResult.value());
model->setData(index, QString::fromStdString(parsedResult.value().ToString()));
view->rebuildCompositeProperty(view->itemFromIndex(index), meta.type, parsedResult.value());
}
}
};
@ -179,7 +221,7 @@ PropertiesView::PropertiesView(QWidget* parent):
setHeaderHidden(true);
setColumnCount(2);
setAlternatingRowColors(true);
setItemDelegate(new CustomItemDelegate(this));
setItemDelegate(new PropertiesItemDelegate(this));
connect(this, &QTreeWidget::itemChanged, this, &PropertiesView::propertyChanged);
connect(this, &QTreeWidget::itemActivated, this, [&](auto* item, int column) {
@ -208,36 +250,12 @@ QModelIndex PropertiesView::indexAt(const QPoint &point) const {
void PropertiesView::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const {
// https://codebrowser.dev/qt5/qtbase/src/widgets/itemviews/qtreeview.cpp.html#312opt
Q_D(const QTreeView);
QStyleOptionViewItem opt = viewOptions();
const QTreeViewItem& viewItem = d->viewItems.at(d->current);
// Taken from source code (above)
bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
&& opt.showDecorationSelected
&& index.parent() == d->hover.parent()
&& index.row() == d->hover.row();
// Un-indent branch
opt.rect = rect;
if (index.parent().isValid())
opt.rect.adjust(0, 0, -indentation(), 0);
opt.state |= QStyle::State_Item;
if (viewItem.hasChildren)
opt.state |= QStyle::State_Children;
if (viewItem.expanded)
opt.state |= QStyle::State_Open;
if (viewItem.hasMoreSiblings || viewItem.parentItem > -1 && d->viewItems.at(viewItem.parentItem).hasMoreSiblings)
opt.state |= QStyle::State_Sibling;
opt.state.setFlag(QStyle::State_MouseOver, hoverRow || d->current == d->hoverBranch);
// Draw background for headings
if (!index.parent().isValid())
painter->fillRect(opt.rect, palette().dark());
painter->fillRect(rect, palette().dark());
style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
QTreeWidget::drawBranches(painter, rect, index);
}
void PropertiesView::setSelected(std::optional<InstanceRef> instance) {
@ -280,6 +298,9 @@ void PropertiesView::setSelected(std::optional<InstanceRef> instance) {
Data::Color3 color = currentValue.get<Data::Color3>();
item->setData(1, Qt::DecorationRole, QColor::fromRgbF(color.R(), color.G(), color.B()));
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} else if (meta.type == &Data::Vector3::TYPE) {
Data::Vector3 vector = currentValue.get<Data::Vector3>();
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
} else {
item->setData(1, Qt::DisplayRole, QString::fromStdString(currentValue.ToString()));
}
@ -288,6 +309,8 @@ void PropertiesView::setSelected(std::optional<InstanceRef> instance) {
item->setDisabled(true);
}
rebuildCompositeProperty(item, meta.type, currentValue);
propertyCategories[meta.category]->addChild(item);
propertyCategories[meta.category]->setExpanded(true);
}
@ -303,7 +326,7 @@ void PropertiesView::setSelected(std::optional<InstanceRef> instance) {
}
void PropertiesView::propertyChanged(QTreeWidgetItem *item, int column) {
if (!item->parent() || !currentInstance || currentInstance->expired()) return;
if (!item->parent() || (item->parent() && item->parent()->parent()) || !currentInstance || currentInstance->expired()) return;
InstanceRef inst = currentInstance->lock();
std::string propertyName = item->data(0, Qt::DisplayRole).toString().toStdString();
@ -312,4 +335,30 @@ void PropertiesView::propertyChanged(QTreeWidgetItem *item, int column) {
if (meta.type == &Data::Bool::TYPE) {
inst->SetPropertyValue(propertyName, Data::Bool(item->checkState(1)));
}
}
void PropertiesView::rebuildCompositeProperty(QTreeWidgetItem *item, const Data::TypeInfo* type, Data::Variant value) {
if (type == &Data::Vector3::TYPE) {
// https://forum.qt.io/post/266837
foreach(auto i, item->takeChildren()) delete i;
Data::Vector3 vector = value.get<Data::Vector3>();
item->setData(1, Qt::DisplayRole, QString::fromStdString(value.ToString()));
QTreeWidgetItem* xItem = new QTreeWidgetItem;
xItem->setData(0, Qt::DisplayRole, "X");
xItem->setData(1, Qt::DisplayRole, vector.X());
QTreeWidgetItem* yItem = new QTreeWidgetItem;
yItem->setData(0, Qt::DisplayRole, "Y");
yItem->setData(1, Qt::DisplayRole, vector.Y());
QTreeWidgetItem* zItem = new QTreeWidgetItem;
zItem->setData(0, Qt::DisplayRole, "Z");
zItem->setData(1, Qt::DisplayRole, vector.Z());
item->addChild(xItem);
item->addChild(yItem);
item->addChild(zItem);
}
}

View file

@ -1,11 +1,12 @@
#pragma once
#include <QTreeWidget>
#include "datatypes/base.h"
#include "objects/base/instance.h"
class Ui_MainWindow;
class CustomItemDelegate;
class PropertiesItemDelegate;
class PropertiesView : public QTreeWidget {
Q_DECLARE_PRIVATE(QTreeView)
@ -13,8 +14,9 @@ class PropertiesView : public QTreeWidget {
std::optional<InstanceRefWeak> currentInstance;
void propertyChanged(QTreeWidgetItem *item, int column);
void activateProperty(QTreeWidgetItem *item, int column);
void rebuildCompositeProperty(QTreeWidgetItem *item, const Data::TypeInfo*, Data::Variant);
friend CustomItemDelegate;
friend PropertiesItemDelegate;
protected:
void drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const override;
QModelIndex indexAt(const QPoint &point) const override;