diff --git a/assets/icons/model.png b/assets/icons/model.png new file mode 100644 index 0000000..0905f93 Binary files /dev/null and b/assets/icons/model.png differ diff --git a/core/src/objects/meta.cpp b/core/src/objects/meta.cpp index 5bdbd1c..613ead5 100644 --- a/core/src/objects/meta.cpp +++ b/core/src/objects/meta.cpp @@ -5,6 +5,7 @@ #include "objects/joint/rotatev.h" #include "objects/joint/weld.h" #include "objects/jointsservice.h" +#include "objects/model.h" #include "objects/part.h" #include "objects/joint/snap.h" #include "objects/script.h" @@ -24,7 +25,8 @@ std::map INSTANCE_MAP = { { "RotateV", &RotateV::TYPE }, { "JointInstance", &JointInstance::TYPE }, { "Script", &Script::TYPE }, - { "Folder", &Folder::TYPE }, + { "Model", &Model::TYPE }, + // { "Folder", &Folder::TYPE }, // Services diff --git a/core/src/objects/model.cpp b/core/src/objects/model.cpp new file mode 100644 index 0000000..1354ad6 --- /dev/null +++ b/core/src/objects/model.cpp @@ -0,0 +1,4 @@ +#include "model.h" + +Model::Model(): Instance(&TYPE) {} +Model::~Model() = default; \ No newline at end of file diff --git a/core/src/objects/model.h b/core/src/objects/model.h new file mode 100644 index 0000000..4e9381c --- /dev/null +++ b/core/src/objects/model.h @@ -0,0 +1,18 @@ +#pragma once + +#include "objects/annotation.h" +#include "objects/base/instance.h" +#include + +// Group object for Parts + +class DEF_INST_(explorer_icon="model") Model : public Instance { + AUTOGEN_PREAMBLE + +public: + Model(); + ~Model(); + + static inline std::shared_ptr New() { return std::make_shared(); }; + static inline std::shared_ptr Create() { return std::make_shared(); }; +}; \ No newline at end of file diff --git a/editor/mainwindow.cpp b/editor/mainwindow.cpp index 7d2c3c8..33514de 100644 --- a/editor/mainwindow.cpp +++ b/editor/mainwindow.cpp @@ -3,6 +3,7 @@ #include "common.h" #include "logger.h" #include "objects/datamodel.h" +#include "objects/model.h" #include "placedocument.h" #include "script/scriptdocument.h" #include @@ -19,6 +20,7 @@ #include #include #include +#include #ifdef _NDEBUG #define NDEBUG @@ -364,6 +366,44 @@ void MainWindow::connectActionHandlers() { } }); + connect(ui->actionGroupObjects, &QAction::triggered, this, [&]() { + auto model = Model::New(); + std::shared_ptr firstParent; + + for (auto object : getSelection()) { + if (firstParent == nullptr && object->GetParent().has_value()) firstParent = object->GetParent().value(); + object->SetParent(model); + } + + if (model->GetChildren().size() == 0) + return; + + // Technically not how it works in the actual studio, but it's not an API-breaking change + // and I think this implementation is more useful so I'm sticking with it + if (firstParent == nullptr) firstParent = gWorkspace(); + model->SetParent(firstParent); + + setSelection({ model }); + }); + + connect(ui->actionUngroupObjects, &QAction::triggered, this, [&]() { + std::vector> newSelection; + + for (auto model : getSelection()) { + // Not a model, skip + if (!model->IsA()) { newSelection.push_back(model); continue; } + + for (auto object : model->GetChildren()) { + object->SetParent(model->GetParent()); + newSelection.push_back(object); + } + + model->Destroy(); + } + + setSelection(newSelection); + }); + connect(ui->actionSaveModel, &QAction::triggered, this, [&]() { std::optional path = openFileDialog("Openblocks Model (*.obm)", ".obm", QFileDialog::AcceptSave); if (!path) return; diff --git a/editor/mainwindow.ui b/editor/mainwindow.ui index ee3ea39..ecfa3ba 100644 --- a/editor/mainwindow.ui +++ b/editor/mainwindow.ui @@ -176,6 +176,8 @@ + + @@ -768,6 +770,40 @@ QAction::MenuRole::NoRole + + + + + + Group Objects + + + Group objects under a Model + + + Ctrl+G + + + QAction::MenuRole::NoRole + + + + + + + + Ungroup Objects + + + Ungroup objects inside selected Model + + + Ctrl+U + + + QAction::MenuRole::NoRole + +