feat(part): added locked property to prevent objects from being selected

This commit is contained in:
maelstrom 2025-04-12 15:15:17 +02:00
parent 07272dbe95
commit ee05b8d9d5
6 changed files with 106 additions and 91 deletions

View file

@ -42,6 +42,7 @@ int main() {
.size = glm::vec3(512, 1.2, 512),
.color = glm::vec3(0.388235, 0.372549, 0.384314),
.anchored = true,
.locked = true,
}));
gWorkspace()->AddChild(lastPart = Part::New({

View file

@ -62,7 +62,7 @@ Part::Part(): Part(PartConstructParams { .color = Data::Color3(0.639216f, 0.6352
}
Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(params.position, params.rotation)),
size(params.size), color(params.color), anchored(params.anchored) {
size(params.size), color(params.color), anchored(params.anchored), locked(params.locked) {
this->memberMap = std::make_unique<MemberMap>(MemberMap {
.super = std::move(this->memberMap),
.members = {
@ -71,6 +71,10 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par
.type = &Data::Bool::TYPE,
.codec = fieldCodecOf<Data::Bool, bool>(),
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
}}, { "Locked", {
.backingField = &locked,
.type = &Data::Bool::TYPE,
.codec = fieldCodecOf<Data::Bool, bool>(),
}}, { "Position", {
.backingField = &cframe,
.type = &Vector3::TYPE,

View file

@ -20,6 +20,7 @@ struct PartConstructParams {
Data::Color3 color;
bool anchored = false;
bool locked = false;
};
class Part : public Instance {
@ -36,6 +37,7 @@ public:
bool selected = false;
bool anchored = false;
bool locked = false;
rp::RigidBody* rigidBody = nullptr;
SurfaceType topSurface = SurfaceType::SurfaceStuds;

View file

@ -282,7 +282,7 @@ void MainGLWidget::handleCursorChange(QMouseEvent* evt) {
};
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
if (rayHit && partFromBody(rayHit->body)->name != "Baseplate") {
if (rayHit && !partFromBody(rayHit->body)->locked) {
setCursor(Qt::OpenHandCursor);
return;
}
@ -341,7 +341,7 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) {
std::optional<const RaycastResult> rayHit = gWorkspace()->CastRayNearest(camera.cameraPos, pointDir, 50000);
if (!rayHit || !partFromBody(rayHit->body)) return;
std::shared_ptr<Part> part = partFromBody(rayHit->body);
if (part->name == "Baseplate") return;
if (part->locked) return;
// Handle surface tool
if (mainWindow()->selectedTool >= TOOL_SMOOTH) {

View file

@ -72,6 +72,99 @@ MainWindow::MainWindow(QWidget *parent)
delete menu;
});
connectActionHandlers();
// Update handles
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
editorToolHandles->adornee = std::nullopt;
if (newSelection.size() == 0) return;
InstanceRef inst = newSelection[0].lock();
if (inst->GetClass() != &Part::TYPE) return;
editorToolHandles->adornee = std::dynamic_pointer_cast<Part>(inst);
});
// Update properties
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
if (newSelection.size() == 0) return;
if (newSelection.size() > 1)
ui->propertiesView->setSelected(std::nullopt);
ui->propertiesView->setSelected(newSelection[0].lock());
});
// ui->explorerView->Init(ui);
// Baseplate
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
.position = glm::vec3(0, -5, 0),
.rotation = glm::vec3(0),
.size = glm::vec3(512, 1.2, 512),
.color = glm::vec3(0.388235, 0.372549, 0.384314),
.anchored = true,
.locked = true,
}));
ui->mainWidget->lastPart->name = "Baseplate";
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
.position = glm::vec3(0),
.rotation = glm::vec3(0.5, 2, 1),
.size = glm::vec3(4, 1.2, 2),
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
}));
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
}
void MainWindow::closeEvent(QCloseEvent* evt) {
#ifdef NDEBUG
// Ask if the user wants to save their changes
// https://stackoverflow.com/a/33890731
QMessageBox msgBox;
msgBox.setText("Save changes before creating new document?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int result = msgBox.exec();
if (result == QMessageBox::Cancel) return evt->ignore();
if (result == QMessageBox::Save) {
std::optional<std::string> path;
if (!gDataModel->HasFile())
path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save " + gDataModel->name));
if (!path || path == "") return evt->ignore();
gDataModel->SaveToFile(path);
}
#endif
}
void MainWindow::handleLog(Logger::LogLevel logLevel, std::string message) {
if (logLevel == Logger::LogLevel::DEBUG) return;
if (logLevel == Logger::LogLevel::INFO)
ui->outputTextView->appendHtml(QString("<p>%1</p>").arg(QString::fromStdString(message)));
if (logLevel == Logger::LogLevel::WARNING)
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 127, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
if (logLevel == Logger::LogLevel::ERROR || logLevel == Logger::LogLevel::FATAL_ERROR)
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 0, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
}
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
void MainWindow::timerEvent(QTimerEvent* evt) {
if (evt->timerId() != timer.timerId()) {
QWidget::timerEvent(evt);
return;
}
float deltaTime = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - lastTime).count();
lastTime = std::chrono::steady_clock::now();
if (simulationPlaying)
gWorkspace()->PhysicsStep(deltaTime);
ui->mainWidget->update();
ui->mainWidget->updateCycle();
}
void MainWindow::connectActionHandlers() {
// Explorer View
ui->explorerView->buildContextMenu();
@ -166,6 +259,7 @@ MainWindow::MainWindow(QWidget *parent)
.size = glm::vec3(512, 1.2, 512),
.color = glm::vec3(0.388235, 0.372549, 0.384314),
.anchored = true,
.locked = true,
}));
ui->mainWidget->lastPart->name = "Baseplate";
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
@ -309,94 +403,6 @@ MainWindow::MainWindow(QWidget *parent)
selectedParent->AddChild(inst.expect());
}
});
// Update handles
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
editorToolHandles->adornee = std::nullopt;
if (newSelection.size() == 0) return;
InstanceRef inst = newSelection[0].lock();
if (inst->GetClass() != &Part::TYPE) return;
editorToolHandles->adornee = std::dynamic_pointer_cast<Part>(inst);
});
// Update properties
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
if (newSelection.size() == 0) return;
if (newSelection.size() > 1)
ui->propertiesView->setSelected(std::nullopt);
ui->propertiesView->setSelected(newSelection[0].lock());
});
// ui->explorerView->Init(ui);
// Baseplate
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
.position = glm::vec3(0, -5, 0),
.rotation = glm::vec3(0),
.size = glm::vec3(512, 1.2, 512),
.color = glm::vec3(0.388235, 0.372549, 0.384314),
.anchored = true,
}));
ui->mainWidget->lastPart->name = "Baseplate";
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
gWorkspace()->AddChild(ui->mainWidget->lastPart = Part::New({
.position = glm::vec3(0),
.rotation = glm::vec3(0.5, 2, 1),
.size = glm::vec3(4, 1.2, 2),
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
}));
gWorkspace()->SyncPartPhysics(ui->mainWidget->lastPart);
}
void MainWindow::closeEvent(QCloseEvent* evt) {
#ifdef NDEBUG
// Ask if the user wants to save their changes
// https://stackoverflow.com/a/33890731
QMessageBox msgBox;
msgBox.setText("Save changes before creating new document?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int result = msgBox.exec();
if (result == QMessageBox::Cancel) return evt->ignore();
if (result == QMessageBox::Save) {
std::optional<std::string> path;
if (!gDataModel->HasFile())
path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save " + gDataModel->name));
if (!path || path == "") return evt->ignore();
gDataModel->SaveToFile(path);
}
#endif
}
void MainWindow::handleLog(Logger::LogLevel logLevel, std::string message) {
if (logLevel == Logger::LogLevel::DEBUG) return;
if (logLevel == Logger::LogLevel::INFO)
ui->outputTextView->appendHtml(QString("<p>%1</p>").arg(QString::fromStdString(message)));
if (logLevel == Logger::LogLevel::WARNING)
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 127, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
if (logLevel == Logger::LogLevel::ERROR || logLevel == Logger::LogLevel::FATAL_ERROR)
ui->outputTextView->appendHtml(QString("<p style=\"color:rgb(255, 0, 0); font-weight: bold;\">%1</p>").arg(QString::fromStdString(message)));
}
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
void MainWindow::timerEvent(QTimerEvent* evt) {
if (evt->timerId() != timer.timerId()) {
QWidget::timerEvent(evt);
return;
}
float deltaTime = std::chrono::duration_cast<std::chrono::duration<float>>(std::chrono::steady_clock::now() - lastTime).count();
lastTime = std::chrono::steady_clock::now();
if (simulationPlaying)
gWorkspace()->PhysicsStep(deltaTime);
ui->mainWidget->update();
ui->mainWidget->updateCycle();
}
void MainWindow::updateToolbars() {

View file

@ -54,6 +54,8 @@ private:
void timerEvent(QTimerEvent*) override;
void closeEvent(QCloseEvent* evt) override;
void handleLog(Logger::LogLevel, std::string);
void connectActionHandlers();
std::optional<std::string> openFileDialog(QString filter, QString defaultExtension, QFileDialog::AcceptMode acceptMode, QString title = "");
};