Release QObject connections on refresh.
This commit is contained in:
parent
48598de9c8
commit
8eaebee2c6
@ -17,11 +17,10 @@
|
|||||||
using namespace Qtk;
|
using namespace Qtk;
|
||||||
|
|
||||||
ToolBox::ToolBox(QWidget * parent) :
|
ToolBox::ToolBox(QWidget * parent) :
|
||||||
QDockWidget(parent), objectDetails_(this),
|
QDockWidget(parent), objectDetails_(this), transformPanel_(this),
|
||||||
transformPanel_(this, "Transform:"), scalePanel_(this, "Scale:"),
|
scalePanel_(this), vertex_(this, "Vertex Shader:"),
|
||||||
vertex_(this, "Vertex Shader:"), fragment_(this, "Fragment Shader:"),
|
fragment_(this, "Fragment Shader:"), properiesForm_(new QFormLayout),
|
||||||
properiesForm_(new QFormLayout), shaderForm_(new QFormLayout),
|
shaderForm_(new QFormLayout), ui(new Ui::ToolBox)
|
||||||
ui(new Ui::ToolBox)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setMinimumWidth(350);
|
setMinimumWidth(350);
|
||||||
@ -51,17 +50,60 @@ void ToolBox::updateFocus(const QString & name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolBox::SpinBox3D::SpinBox3D(QLayout * layout, const char * l) :
|
ToolBox::SpinBox3D::SpinBox3D(QWidget * parent, const char * l) :
|
||||||
label(new QLabel(tr(l))), x(new QDoubleSpinBox), y(new QDoubleSpinBox),
|
QWidget(parent), layout(new QHBoxLayout(this)), label(new QLabel(tr(l)))
|
||||||
z(new QDoubleSpinBox), fields({x, y, z})
|
|
||||||
{
|
{
|
||||||
// The layout owns the widget and will clean it up on destruction.
|
// The layout owns the widget and will clean it up on destruction.
|
||||||
layout->addWidget(label);
|
layout->addWidget(label);
|
||||||
for (const auto & f : fields) {
|
for (const auto & f : fields) {
|
||||||
layout->addWidget(f);
|
layout->addWidget(f->spinBox);
|
||||||
f->setMinimum(std::numeric_limits<double>::lowest());
|
f->spinBox->setMinimum(std::numeric_limits<double>::lowest());
|
||||||
f->setSingleStep(0.1);
|
f->spinBox->setSingleStep(0.1);
|
||||||
f->setFixedWidth(75);
|
f->spinBox->setFixedWidth(75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToolBox::SpinBox::disconnect() const
|
||||||
|
{
|
||||||
|
Object::disconnect(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToolBox::TransformPanel::setObject(const Qtk::Object * object)
|
||||||
|
{
|
||||||
|
// Reconnect translation panel controls to the new object.
|
||||||
|
const std::vector binds = {&Object::setTranslationX,
|
||||||
|
&Object::setTranslationY,
|
||||||
|
&Object::setTranslationZ};
|
||||||
|
for (size_t i = 0; i < spinBox3D.fields.size(); i++) {
|
||||||
|
auto * f = spinBox3D.fields[i];
|
||||||
|
// Disconnect before changing spin box value.
|
||||||
|
f->disconnect();
|
||||||
|
|
||||||
|
// Set the values in the spin box to the object's current X,Y,Z
|
||||||
|
f->spinBox->setValue(object->getTransform().getTranslation()[i]);
|
||||||
|
|
||||||
|
// Reconnect to bind spin box value to the new object's position.
|
||||||
|
f->connection =
|
||||||
|
connect(f->spinBox, &QDoubleSpinBox::valueChanged, object, binds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToolBox::ScalePanel::setObject(const Qtk::Object * object)
|
||||||
|
{
|
||||||
|
// Reconnect scale panel controls to the new object.
|
||||||
|
const std::vector binds = {
|
||||||
|
&Object::setScaleX, &Object::setScaleY, &Object::setScaleZ};
|
||||||
|
for (size_t i = 0; i < spinBox3D.fields.size(); i++) {
|
||||||
|
auto * f = spinBox3D.fields[i];
|
||||||
|
// Disconnect before changing spin box value.
|
||||||
|
f->disconnect();
|
||||||
|
|
||||||
|
// Set the values in the spin box to the object's current X,Y,Z
|
||||||
|
f->spinBox->setValue(object->getTransform().getScale()[i]);
|
||||||
|
|
||||||
|
// Reconnect to bind spin box value to the new object's scale.
|
||||||
|
f->connection =
|
||||||
|
connect(f->spinBox, &QDoubleSpinBox::valueChanged, object, binds[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,44 +114,11 @@ ToolBox::~ToolBox()
|
|||||||
|
|
||||||
void ToolBox::refreshProperties(const Object * object)
|
void ToolBox::refreshProperties(const Object * object)
|
||||||
{
|
{
|
||||||
objectDetails_.setDetails(object);
|
// Refresh to show the new object's details.
|
||||||
|
objectDetails_.setObject(object);
|
||||||
// Reconnect transform panel controls to the new object.
|
// Reconnect transform panel controls to the new object.
|
||||||
connect(transformPanel_.spinBox.x,
|
transformPanel_.setObject(object);
|
||||||
&QDoubleSpinBox::valueChanged,
|
scalePanel_.setObject(object);
|
||||||
object,
|
|
||||||
&Object::setTranslationX);
|
|
||||||
connect(transformPanel_.spinBox.y,
|
|
||||||
&QDoubleSpinBox::valueChanged,
|
|
||||||
object,
|
|
||||||
&Object::setTranslationY);
|
|
||||||
connect(transformPanel_.spinBox.z,
|
|
||||||
&QDoubleSpinBox::valueChanged,
|
|
||||||
object,
|
|
||||||
&Object::setTranslationZ);
|
|
||||||
// Set the values in the spin box to the object's current X,Y,Z position.
|
|
||||||
auto transform = object->getTransform();
|
|
||||||
for (size_t i = 0; i < 3; i++) {
|
|
||||||
transformPanel_.spinBox.fields[i]->setValue(transform.getTranslation()[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolBox::refreshShaders(const Object * object)
|
void ToolBox::refreshShaders(const Object * object)
|
||||||
|
@ -84,7 +84,8 @@ namespace Qtk
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDetails(const Qtk::Object * object)
|
/// Refresh to display the new object's details
|
||||||
|
void setObject(const Qtk::Object * object)
|
||||||
{
|
{
|
||||||
name.setItem(tr("Name:"), object->getName());
|
name.setItem(tr("Name:"), object->getName());
|
||||||
objectType.setItem(
|
objectType.setItem(
|
||||||
@ -96,32 +97,67 @@ namespace Qtk
|
|||||||
};
|
};
|
||||||
ObjectDetails objectDetails_;
|
ObjectDetails objectDetails_;
|
||||||
|
|
||||||
/// Spinbox with 3 fields and label.
|
/// Structure to associate a QSpinBox with a connection.
|
||||||
struct SpinBox3D {
|
struct SpinBox {
|
||||||
/// We pass a layout to ensure Qt will clean up resources.
|
/**
|
||||||
explicit SpinBox3D(QLayout * layout, const char * l = "SpinBox3D:");
|
* Default constructor passes no parent to the QSpinBox.
|
||||||
|
* It must be added to a layout for Qt to clean up the resources.
|
||||||
|
*/
|
||||||
|
SpinBox() : spinBox(new QDoubleSpinBox) {}
|
||||||
|
|
||||||
QLabel * label;
|
/// Disconnect the associated connection.
|
||||||
QDoubleSpinBox * x;
|
void disconnect() const;
|
||||||
QDoubleSpinBox * y;
|
|
||||||
QDoubleSpinBox * z;
|
QDoubleSpinBox * spinBox;
|
||||||
std::array<QDoubleSpinBox *, 3> fields;
|
QMetaObject::Connection connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Transform controls and layout.
|
/// Spinbox with 3 fields and a single label.
|
||||||
class SpinBoxHorizontal3D : QWidget
|
class SpinBox3D final : QWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SpinBoxHorizontal3D(
|
/// We pass a parent to ensure Qt will clean up resources.
|
||||||
QWidget * parent, const char * l = "SpinBoxHorizontal3D:") :
|
/// Assigning a QWidget to a QLayout also ensures Qt will clean up.
|
||||||
QWidget(parent), layout(new QHBoxLayout(this)), spinBox(layout, l)
|
explicit SpinBox3D(QWidget * parent, const char * l = "SpinBox3D:");
|
||||||
|
|
||||||
|
/// The main layout for the SpinBox3D widget.
|
||||||
|
QHBoxLayout * layout {this};
|
||||||
|
|
||||||
|
/// Label for the SpinBox3D.
|
||||||
|
QLabel * label;
|
||||||
|
|
||||||
|
/// SpinBox and a connection for each field.
|
||||||
|
SpinBox x, y, z;
|
||||||
|
/// Array for iterating over fields.
|
||||||
|
std::array<SpinBox *, 3> fields {&x, &y, &z};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Initialize the transform panel and configure QObject connections.
|
||||||
|
struct TransformPanel {
|
||||||
|
explicit TransformPanel(QWidget * parent) :
|
||||||
|
spinBox3D(parent, "Transform:")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
QHBoxLayout * layout;
|
|
||||||
SpinBox3D spinBox;
|
|
||||||
};
|
|
||||||
SpinBoxHorizontal3D transformPanel_, scalePanel_;
|
|
||||||
|
|
||||||
|
/// Reconnect QObject connections and spin box values in UI.
|
||||||
|
void setObject(const Qtk::Object * object);
|
||||||
|
|
||||||
|
SpinBox3D spinBox3D;
|
||||||
|
};
|
||||||
|
TransformPanel transformPanel_;
|
||||||
|
|
||||||
|
/// Initialize the scale panel and configure QObject connections.
|
||||||
|
struct ScalePanel {
|
||||||
|
explicit ScalePanel(QWidget * parent) : spinBox3D(parent, "Scale:") {}
|
||||||
|
|
||||||
|
/// Reconnect QObject connections and spin box values in UI.
|
||||||
|
void setObject(const Qtk::Object * object);
|
||||||
|
|
||||||
|
SpinBox3D spinBox3D;
|
||||||
|
};
|
||||||
|
ScalePanel scalePanel_;
|
||||||
|
|
||||||
|
/// Displays shader name, path, and read-only text view.
|
||||||
class ShaderView final : QWidget
|
class ShaderView final : QWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -130,17 +166,23 @@ namespace Qtk
|
|||||||
layout(new QVBoxLayout(this)), path(parent, l),
|
layout(new QVBoxLayout(this)), path(parent, l),
|
||||||
editor(new QTextEdit(parent))
|
editor(new QTextEdit(parent))
|
||||||
{
|
{
|
||||||
|
// Create a child horizontal layout for shader name and file path.
|
||||||
auto * pathLayout = new QHBoxLayout;
|
auto * pathLayout = new QHBoxLayout;
|
||||||
pathLayout->addWidget(path.label);
|
pathLayout->addWidget(path.label);
|
||||||
pathLayout->addWidget(path.value);
|
pathLayout->addWidget(path.value);
|
||||||
layout->addLayout(pathLayout);
|
layout->addLayout(pathLayout);
|
||||||
layout->addWidget(editor);
|
|
||||||
|
// Add the read-only text editor widget to the main layout.
|
||||||
editor->setReadOnly(true);
|
editor->setReadOnly(true);
|
||||||
|
layout->addWidget(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The main layout for the ShaderView widget.
|
||||||
QVBoxLayout * layout;
|
QVBoxLayout * layout;
|
||||||
|
|
||||||
/// Shader name and path on disk.
|
/// Shader name and path on disk.
|
||||||
ObjectDetails::Item path;
|
ObjectDetails::Item path;
|
||||||
|
|
||||||
/// Read-only (for now) display of the shader source code.
|
/// Read-only (for now) display of the shader source code.
|
||||||
QTextEdit * editor;
|
QTextEdit * editor;
|
||||||
};
|
};
|
||||||
|
@ -244,6 +244,21 @@ namespace Qtk
|
|||||||
mProgram.release();
|
mProgram.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Public Static Methods
|
||||||
|
************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to disconnect a QObject connection, only if it's valid.
|
||||||
|
* If the connection is valid and we fail to disconnect log a message.
|
||||||
|
*/
|
||||||
|
static void disconnect(const QMetaObject::Connection & con)
|
||||||
|
{
|
||||||
|
if (con && !QObject::disconnect(con)) {
|
||||||
|
qDebug() << "[Qtk] Failed to disconnect valid connection: " << con;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* Private Members
|
* Private Members
|
||||||
|
Loading…
x
Reference in New Issue
Block a user