Refresh object details without reloading widget.

+ Clean up ToolBox widget tree.
This commit is contained in:
Shaun Reed 2025-03-23 15:31:00 -04:00
parent 034d0a8b4e
commit 6218928e15
2 changed files with 121 additions and 138 deletions

View File

@ -17,20 +17,53 @@
using namespace Qtk;
ToolBox::ToolBox(QWidget * parent) :
QDockWidget(parent), objectDetails_(this), ui(new Ui::ToolBox)
QDockWidget(parent), objectDetails_(this),
transformPanel_(this, "Transform:"), scalePanel_(this, "Scale:"),
vertex_(this, "Vertex Shader:"), fragment_(this, "Fragment Shader:"),
properiesForm_(new QFormLayout), shaderForm_(new QFormLayout),
ui(new Ui::ToolBox)
{
ui->setupUi(this);
setMinimumWidth(350);
// Object Properties.
ui->page_properties->setLayout(properiesForm_);
properiesForm_->addRow(objectDetails_.name.label, objectDetails_.name.value);
properiesForm_->addRow(objectDetails_.objectType.label,
objectDetails_.objectType.value);
properiesForm_->addRow(reinterpret_cast<QWidget *>(&transformPanel_));
properiesForm_->addRow(reinterpret_cast<QWidget *>(&scalePanel_));
ui->toolBox->setCurrentWidget(ui->page_properties);
// Shader views.
ui->page_shaders->setLayout(shaderForm_);
shaderForm_->addRow(vertex_.path.label, vertex_.path.value);
shaderForm_->addRow(vertex_.editor);
shaderForm_->addRow(fragment_.path.label, fragment_.path.value);
shaderForm_->addRow(fragment_.editor);
}
void ToolBox::updateFocus(const QString & name)
{
auto object =
Qtk::QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name);
QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name);
if (object != Q_NULLPTR) {
removePages();
createPageProperties(object);
createPageShader(object);
refreshProperties(object);
refreshShaders(object);
}
}
ToolBox::SpinBox3D::SpinBox3D(QLayout * layout, const char * l) :
label(new QLabel(tr(l))), x(new QDoubleSpinBox), y(new QDoubleSpinBox),
z(new QDoubleSpinBox), fields({x, y, z})
{
// The layout owns the widget and will clean it up on destruction.
layout->addWidget(label);
for (const auto & f : fields) {
layout->addWidget(f);
f->setMinimum(std::numeric_limits<double>::lowest());
f->setSingleStep(0.1);
f->setFixedWidth(75);
}
}
@ -39,121 +72,52 @@ ToolBox::~ToolBox()
delete ui;
}
void ToolBox::removePages()
void ToolBox::refreshProperties(const Object * object)
{
// Remove all existing pages.
for (size_t i = 0; i < ui->toolBox->count(); i++) {
delete ui->toolBox->widget(i);
ui->toolBox->removeItem(i);
}
}
objectDetails_.setDetails(object);
void ToolBox::createTransformPanel(const Object * object)
{
auto rowLayout = transformPanel_.layout = new QHBoxLayout;
transformPanel_.spinBox.label = new QLabel(tr("Translation:"));
rowLayout->addWidget(transformPanel_.spinBox.label);
int minWidth = 75;
for (size_t i = 0; i < 3; i++) {
QDoubleSpinBox * spinBox;
if (i == 0) {
spinBox = transformPanel_.spinBox.x = new QDoubleSpinBox;
connect(spinBox,
// Reconnect transform panel controls to the new object.
connect(transformPanel_.spinBox.x,
&QDoubleSpinBox::valueChanged,
object,
&Object::setTranslationX);
} else if (i == 1) {
spinBox = transformPanel_.spinBox.y = new QDoubleSpinBox;
connect(spinBox,
connect(transformPanel_.spinBox.y,
&QDoubleSpinBox::valueChanged,
object,
&Object::setTranslationY);
} else if (i == 2) {
spinBox = transformPanel_.spinBox.z = new QDoubleSpinBox;
connect(spinBox,
connect(transformPanel_.spinBox.z,
&QDoubleSpinBox::valueChanged,
object,
&Object::setTranslationZ);
}
spinBox->setMinimum(std::numeric_limits<double>::lowest());
spinBox->setSingleStep(0.1);
spinBox->setValue(object->getTransform().getTranslation()[i]);
spinBox->setFixedWidth(minWidth);
rowLayout->addWidget(spinBox);
}
// Add the layout for this panel to the layout for the primary widget.
formLayout_->addRow(transformPanel_.layout);
}
void ToolBox::createPageProperties(const Object * object)
{
// Set the values in the spin box to the object's current X,Y,Z position.
auto transform = object->getTransform();
auto * widget = new QWidget;
formLayout_ = new QFormLayout;
widget->setLayout(formLayout_);
ui->toolBox->addItem(widget, "Properties");
ui->toolBox->setCurrentWidget(widget);
objectDetails_.setDetails(object);
// TODO: Do this in ToolBox ctor after initializing the form.
formLayout_->addRow(objectDetails_.name.label, objectDetails_.name.value);
formLayout_->addRow(objectDetails_.objectType.label,
objectDetails_.objectType.value);
createTransformPanel(object);
int minWidth = 75;
auto rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel(tr("Scale:")));
for (size_t i = 0; i < 3; i++) {
auto spinBox = new QDoubleSpinBox;
spinBox->setMinimum(std::numeric_limits<double>::lowest());
spinBox->setSingleStep(0.1);
spinBox->setValue(transform.getScale()[i]);
spinBox->setFixedWidth(minWidth);
rowLayout->addWidget(spinBox);
transformPanel_.spinBox.fields[i]->setValue(transform.getTranslation()[i]);
}
if (i == 0) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleX);
} else if (i == 1) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleY);
} else if (i == 2) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleZ);
// Reconnect scale panel controls to the new object.
connect(scalePanel_.spinBox.x,
&QDoubleSpinBox::valueChanged,
object,
&Object::setScaleX);
connect(scalePanel_.spinBox.y,
&QDoubleSpinBox::valueChanged,
object,
&Object::setScaleY);
connect(scalePanel_.spinBox.z,
&QDoubleSpinBox::valueChanged,
object,
&Object::setScaleZ);
// Set the values in the spin box to the object's current X,Y,Z scale.
for (size_t i = 0; i < 3; i++) {
scalePanel_.spinBox.fields[i]->setValue(transform.getScale()[i]);
}
}
formLayout_->addRow(rowLayout);
}
void ToolBox::createPageShader(const Object * object)
void ToolBox::refreshShaders(const Object * object)
{
// Shaders page.
auto widget = new QWidget;
ui->toolBox->addItem(widget, "Shaders");
auto mainLayout = new QFormLayout;
auto rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel("Vertex Shader:"));
rowLayout->addWidget(new QLabel(object->getVertexShader().c_str()));
mainLayout->addRow(rowLayout);
auto shaderView = new QTextEdit;
shaderView->setReadOnly(true);
shaderView->setText(object->getVertexShaderSourceCode().c_str());
mainLayout->addRow(shaderView);
rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel("Fragment Shader:"));
rowLayout->addWidget(new QLabel(object->getFragmentShader().c_str()));
mainLayout->addRow(rowLayout);
shaderView = new QTextEdit;
shaderView->setReadOnly(true);
shaderView->setText(object->getFragmentShaderSourceCode().c_str());
mainLayout->addRow(shaderView);
widget->setLayout(mainLayout);
vertex_.path.setItem(object->getVertexShader().c_str());
vertex_.editor->setText(object->getVertexShaderSourceCode().c_str());
fragment_.path.setItem(object->getFragmentShader().c_str());
fragment_.editor->setText(object->getFragmentShaderSourceCode().c_str());
}

View File

@ -16,6 +16,7 @@
#include <QFormLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QTextEdit>
#include "qtk/scene.h"
@ -27,7 +28,7 @@ namespace Ui
namespace Qtk
{
class ToolBox : public QDockWidget
class ToolBox final : public QDockWidget
{
Q_OBJECT
@ -40,18 +41,9 @@ namespace Qtk
~ToolBox();
void removePages();
void refreshProperties(const Object * object);
/**
* Creates the transform panel and controls.
*
* @param object The Qtk::Object associated with this panel.
*/
void createTransformPanel(const Object * object);
void createPageProperties(const Object * object);
void createPageShader(const Object * object);
void refreshShaders(const Object * object);
void updateFocus(const QString & name);
@ -65,11 +57,17 @@ namespace Qtk
struct ObjectDetails {
/// Single item containing a label and value.
struct Item {
explicit Item(QWidget * parent) :
label(new QLabel(parent)), value(new QLabel(parent))
explicit Item(QWidget * parent,
const char * l = "Item:",
const char * v = "") :
label(new QLabel(tr(l), parent)),
value(new QLabel(tr(v), parent))
{
value->setText(v);
}
void setItem(const QString & v) { setItem(label->text(), v); }
void setItem(const QString & l, const QString & v)
{
label->setText(l);
@ -82,7 +80,7 @@ namespace Qtk
/// We pass the parent widget so that Qt handles releasing memory.
explicit ObjectDetails(QWidget * parent) :
name(parent), objectType(parent)
name(parent, "Name:"), objectType(parent, "ObjectType:")
{
}
@ -100,28 +98,49 @@ namespace Qtk
/// Spinbox with 3 fields and label.
struct SpinBox3D {
/// We pass a layout to ensure Qt will clean up resources.
explicit SpinBox3D(QLayout * layout, const char * l = "SpinBox3D:");
QLabel * label;
QDoubleSpinBox * x;
QDoubleSpinBox * y;
QDoubleSpinBox * z;
std::array<QDoubleSpinBox *, 3> fields;
};
/// Transform controls and layout.
struct TransformPanel {
class SpinBoxHorizontal3D : QWidget
{
public:
explicit SpinBoxHorizontal3D(
QWidget * parent, const char * l = "SpinBoxHorizontal3D:") :
QWidget(parent), layout(new QHBoxLayout(this)), spinBox(layout, l)
{
}
QHBoxLayout * layout;
SpinBox3D spinBox;
};
TransformPanel transformPanel_;
SpinBoxHorizontal3D transformPanel_, scalePanel_;
/// Scale controls and layout.
struct ScalePanel {
QHBoxLayout * layout;
SpinBox3D spinBox;
class ShaderView
{
public:
explicit ShaderView(QWidget * parent = nullptr,
const char * l = "ShaderView:") :
path(parent, l), editor(new QTextEdit(parent))
{
editor->setReadOnly(true);
}
/// Shader name and path on disk.
ObjectDetails::Item path;
/// Read-only (for now) display of the shader source code.
QTextEdit * editor;
};
ScalePanel scalePanel_;
ShaderView vertex_, fragment_;
/// The root layout for the primary widget.
QFormLayout * formLayout_;
QFormLayout * properiesForm_;
QFormLayout * shaderForm_;
Ui::ToolBox * ui;
};