ToolBar buttons to add and remove objects. (#18)

This commit is contained in:
Shaun Reed 2025-04-12 16:53:40 +00:00
parent f40366cb8d
commit ed604eb655
7 changed files with 173 additions and 17 deletions

View File

@ -48,6 +48,16 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent)
&Qtk::ToolBox::updateFocus); &Qtk::ToolBox::updateFocus);
} }
connect(ui_->actionDelete_Object,
&QAction::triggered,
this,
&MainWindow::deleteObject);
connect(ui_->actionLoad_Model,
&QAction::triggered,
this,
&MainWindow::loadObject);
// TODO: Fix / use MainWindow in Qt Designer to add these dock widgets. // TODO: Fix / use MainWindow in Qt Designer to add these dock widgets.
// For now we will add them manually, but we should be able to do this in the // For now we will add them manually, but we should be able to do this in the
// designer. At the moment if you edit the UI in designer the dock widget // designer. At the moment if you edit the UI in designer the dock widget
@ -104,6 +114,26 @@ void MainWindow::refreshScene(const QString & sceneName)
ui_->qtk__TreeView->updateView(getQtkWidget()->getScene()); ui_->qtk__TreeView->updateView(getQtkWidget()->getScene());
} }
void MainWindow::deleteObject()
{
if (auto object = ui_->qtk__ToolBox->getObjectFocus(); object != Q_NULLPTR) {
auto scene = getQtkWidget()->getScene();
switch (object->getType()) {
case Qtk::Object::Type::QTK_MESH:
scene->removeObject(dynamic_cast<Qtk::MeshRenderer *>(object));
ui_->qtk__ToolBox->clearFocus();
break;
case Qtk::Object::Type::QTK_MODEL:
scene->removeObject(dynamic_cast<Qtk::Model *>(object));
ui_->qtk__ToolBox->clearFocus();
break;
default:
qDebug() << "Failed to delete model with invalid type";
break;
}
}
}
void MainWindow::setScene(Qtk::Scene * scene) void MainWindow::setScene(Qtk::Scene * scene)
{ {
connect(scene, connect(scene,

View File

@ -11,8 +11,8 @@
#include <unordered_map> #include <unordered_map>
#include <QFileDialog>
#include <QMainWindow> #include <QMainWindow>
#include <QPlainTextEdit>
#include "designer-plugins/debugconsole.h" #include "designer-plugins/debugconsole.h"
@ -144,6 +144,23 @@ class MainWindow : public QMainWindow
*/ */
void refreshScene(const QString & sceneName); void refreshScene(const QString & sceneName);
/**
* Opens a QFileDialog for selecting an object file to load into the scene.
*/
void loadObject()
{
const QUrl file = QFileDialog::getOpenFileName(
this, tr("Load Model"), QDir::homePath(), tr("Object Files (*.obj)"));
getQtkWidget()->getScene()->loadModel(file.fileName().replace(".obj", ""),
file.toString());
}
/**
* Deletes the currently selected object from the scene.
*/
void deleteObject();
private: private:
/*************************************************************************** /***************************************************************************
* Private Members * Private Members

View File

@ -223,7 +223,7 @@
</action> </action>
<action name="actionLoad_Model"> <action name="actionLoad_Model">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>true</bool>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset>
@ -238,7 +238,7 @@
</action> </action>
<action name="actionDelete_Object"> <action name="actionDelete_Object">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>true</bool>
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset>

View File

@ -20,7 +20,7 @@ ToolBox::ToolBox(QWidget * parent) :
QDockWidget(parent), objectDetails_(this), transformPanel_(this), QDockWidget(parent), objectDetails_(this), transformPanel_(this),
scalePanel_(this), vertex_(this, "Vertex Shader:"), scalePanel_(this), vertex_(this, "Vertex Shader:"),
fragment_(this, "Fragment Shader:"), properiesForm_(new QFormLayout), fragment_(this, "Fragment Shader:"), properiesForm_(new QFormLayout),
shaderForm_(new QFormLayout), ui(new Ui::ToolBox) shaderForm_(new QFormLayout), ui(new Ui::ToolBox), objectFocus_(Q_NULLPTR)
{ {
ui->setupUi(this); ui->setupUi(this);
setMinimumWidth(350); setMinimumWidth(350);
@ -44,10 +44,24 @@ void ToolBox::updateFocus(const QString & name)
{ {
auto object = auto object =
QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name); QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name);
if (object != Q_NULLPTR) { // If we can't find the object show a warning.
refreshProperties(object); if (object == Q_NULLPTR) {
refreshShaders(object); qDebug() << "Failed to find selected object: " << name
<< "; Clearing object panels.";
} }
// We should still pass the nullptr here if we failed to find the object
// above.
objectFocus_ = object;
refreshProperties(object);
refreshShaders(object);
}
void ToolBox::clearFocus()
{
objectFocus_ = Q_NULLPTR;
refreshProperties(objectFocus_);
refreshShaders(objectFocus_);
} }
ToolBox::SpinBox3D::SpinBox3D(QWidget * parent, const char * l) : ToolBox::SpinBox3D::SpinBox3D(QWidget * parent, const char * l) :
@ -70,6 +84,13 @@ void ToolBox::SpinBox::disconnect() const
void ToolBox::TransformPanel::setObject(const Qtk::Object * object) void ToolBox::TransformPanel::setObject(const Qtk::Object * object)
{ {
// Zero the panel contents if there is no object selected.
if (object == Q_NULLPTR) {
spinBox3D.clear();
return;
}
// Reconnect translation panel controls to the new object. // Reconnect translation panel controls to the new object.
const std::vector binds = {&Object::setTranslationX, const std::vector binds = {&Object::setTranslationX,
&Object::setTranslationY, &Object::setTranslationY,
@ -90,6 +111,12 @@ void ToolBox::TransformPanel::setObject(const Qtk::Object * object)
void ToolBox::ScalePanel::setObject(const Qtk::Object * object) void ToolBox::ScalePanel::setObject(const Qtk::Object * object)
{ {
// Zero the panel contents if there is no object selected.
if (object == Q_NULLPTR) {
spinBox3D.clear();
return;
}
// Reconnect scale panel controls to the new object. // Reconnect scale panel controls to the new object.
const std::vector binds = { const std::vector binds = {
&Object::setScaleX, &Object::setScaleY, &Object::setScaleZ}; &Object::setScaleX, &Object::setScaleY, &Object::setScaleZ};
@ -123,8 +150,21 @@ void ToolBox::refreshProperties(const Object * object)
void ToolBox::refreshShaders(const Object * object) void ToolBox::refreshShaders(const Object * object)
{ {
// Zero the panel contents if there is no object selected.
if (object == Q_NULLPTR) {
vertex_.clear();
fragment_.clear();
return;
}
vertex_.path.setValue(object->getVertexShader().c_str()); vertex_.path.setValue(object->getVertexShader().c_str());
vertex_.editor->setText(object->getVertexShaderSourceCode().c_str()); vertex_.editor->setText(object->getVertexShaderSourceCode().c_str());
fragment_.path.setValue(object->getFragmentShader().c_str()); fragment_.path.setValue(object->getFragmentShader().c_str());
fragment_.editor->setText(object->getFragmentShaderSourceCode().c_str()); fragment_.editor->setText(object->getFragmentShaderSourceCode().c_str());
} }
void ToolBox::refresh(const Object * object)
{
refreshProperties(object);
refreshShaders(object);
}

View File

@ -18,8 +18,8 @@
#include <QLabel> #include <QLabel>
#include <QTextEdit> #include <QTextEdit>
#include "qtk/object.h"
#include "qtk/scene.h"
namespace Ui namespace Ui
{ {
@ -45,8 +45,13 @@ namespace Qtk
void refreshShaders(const Object * object); void refreshShaders(const Object * object);
void refresh(const Object * object);
void updateFocus(const QString & name); void updateFocus(const QString & name);
[[nodiscard]] Object * getObjectFocus() const { return objectFocus_; }
void clearFocus();
private: private:
/************************************************************************* /*************************************************************************
@ -65,9 +70,9 @@ namespace Qtk
{ {
} }
void setValue(const char * v) { value->setText(tr(v)); } void setValue(const char * v) const { value->setText(tr(v)); }
void setItem(const char * l, const char * v) void setItem(const char * l, const char * v) const
{ {
label->setText(tr(l)); label->setText(tr(l));
value->setText(tr(v)); value->setText(tr(v));
@ -84,8 +89,14 @@ namespace Qtk
} }
/// Refresh to display the new object's details /// Refresh to display the new object's details
void setObject(const Qtk::Object * object) void setObject(const Qtk::Object * object) const
{ {
// Zero contents if there is no object selected.
if (object == Q_NULLPTR) {
name.setValue("");
objectType.setValue("No object selected");
return;
}
name.setItem("Name:", object->getName().toStdString().c_str()); name.setItem("Name:", object->getName().toStdString().c_str());
objectType.setItem( objectType.setItem(
"Type:", "Type:",
@ -119,6 +130,15 @@ namespace Qtk
/// Assigning a QWidget to a QLayout also ensures Qt will clean up. /// Assigning a QWidget to a QLayout also ensures Qt will clean up.
explicit SpinBox3D(QWidget * parent, const char * l = "SpinBox3D:"); explicit SpinBox3D(QWidget * parent, const char * l = "SpinBox3D:");
/// Zero the SpinBox3D display.
void clear()
{
for (auto & field : fields) {
field->disconnect();
field->spinBox->setValue(0.0);
}
}
/// The main layout for the SpinBox3D widget. /// The main layout for the SpinBox3D widget.
QHBoxLayout * layout; QHBoxLayout * layout;
@ -176,6 +196,13 @@ namespace Qtk
layout->addWidget(editor); layout->addWidget(editor);
} }
/// Zero the ShaderView display.
void clear() const
{
path.setValue("");
editor->setText("");
}
/// The main layout for the ShaderView widget. /// The main layout for the ShaderView widget.
QVBoxLayout * layout; QVBoxLayout * layout;
@ -190,6 +217,8 @@ namespace Qtk
QFormLayout * properiesForm_; QFormLayout * properiesForm_;
QFormLayout * shaderForm_; QFormLayout * shaderForm_;
Object * objectFocus_ {};
Ui::ToolBox * ui; Ui::ToolBox * ui;
}; };
} // namespace Qtk } // namespace Qtk

View File

@ -55,6 +55,34 @@ template <> Model * Scene::addObject(Model * object)
return object; return object;
} }
template <> void Scene::removeObject(MeshRenderer * object)
{
auto it = std::find(mMeshes.begin(), mMeshes.end(), object);
if (it == mMeshes.end()) {
qDebug() << "[Scene::removeObject]: Failed to remove object: "
<< object->getName() << " (" << object << ")";
return;
}
--mObjectCount[object->getName()];
mMeshes.erase(it);
emit sceneUpdated(mSceneName);
}
template <> void Scene::removeObject(Model * object)
{
auto it = std::find(mModels.begin(), mModels.end(), object);
if (it == mModels.end()) {
qDebug() << "[Scene::removeObject]: Failed to remove object: "
<< object->getName() << " (" << object << ")";
return;
}
--mObjectCount[object->getName()];
mModels.erase(it);
emit sceneUpdated(mSceneName);
}
void Scene::draw() void Scene::draw()
{ {
if (!mInit) { if (!mInit) {

View File

@ -85,16 +85,16 @@ namespace Qtk
void loadModel(const QUrl & url) void loadModel(const QUrl & url)
{ {
auto fileName = url.fileName().replace(".obj", "").toStdString(); auto fileName = url.fileName().replace(".obj", "");
auto filePath = url.toLocalFile().toStdString(); auto filePath = url.toLocalFile();
loadModel(fileName, filePath); loadModel(fileName, filePath);
} }
void loadModel(const std::string & name, const std::string & path) void loadModel(const QString & name, const QString & path)
{ {
// Add the dropped model to the load queue. // Add the dropped model to the load queue.
// This is consumed during rendering of the scene if not empty. // This is consumed during rendering of the scene if not empty.
mModelLoadQueue.emplace(name, path); mModelLoadQueue.emplace(name.toStdString(), path.toStdString());
} }
/************************************************************************* /*************************************************************************
@ -182,8 +182,9 @@ namespace Qtk
/** /**
* Adds objects to the scene. * Adds objects to the scene.
* This template provides explicit specializations for valid types. * This template provides explicit specializations for the valid types:
* Adding any object other than these types will cause errors. * MeshRenderer, Model
* Any other object type will cause errors.
* TODO: Refactor to use Object base class container for scene objects. * TODO: Refactor to use Object base class container for scene objects.
* *
* If creating a new object type for a scene, it must inherit Qtk::Object * If creating a new object type for a scene, it must inherit Qtk::Object
@ -194,6 +195,17 @@ namespace Qtk
*/ */
template <typename T> T * addObject(T * object); template <typename T> T * addObject(T * object);
/**
* Removes an object from the scene.
* This template provides explicit specializations for the valid types:
* MeshRenderer, Model
* Any other object type will cause errors.
* TODO: Refactor to use Object base class container for scene objects.
*
* @param object Pointer to the object to remove from the scene.
*/
template <typename T> void removeObject(T * object);
/** /**
* @param name The name to use for this scene. * @param name The name to use for this scene.
*/ */