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