2024-11-25 21:20:39 +00:00
|
|
|
#include "mainwindow.h"
|
|
|
|
#include "./ui_mainwindow.h"
|
|
|
|
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QProcess>
|
|
|
|
#include <QThread>
|
2024-12-01 12:08:45 +00:00
|
|
|
#include <QTimerEvent>
|
|
|
|
#include <QMouseEvent>
|
|
|
|
#include <QWidget>
|
2025-01-18 15:27:43 +00:00
|
|
|
#include <QTreeView>
|
|
|
|
#include <QAbstractItemView>
|
2025-02-18 21:50:16 +00:00
|
|
|
#include <memory>
|
2025-01-28 20:27:33 +00:00
|
|
|
#include <optional>
|
2024-12-01 12:08:45 +00:00
|
|
|
|
|
|
|
#include "common.h"
|
2025-02-02 23:23:25 +00:00
|
|
|
#include "editorcommon.h"
|
2025-02-06 17:58:00 +00:00
|
|
|
#include "objects/base/instance.h"
|
|
|
|
#include "objects/datamodel.h"
|
2024-12-01 12:08:45 +00:00
|
|
|
#include "physics/simulation.h"
|
2025-01-17 08:24:18 +00:00
|
|
|
#include "objects/part.h"
|
2025-02-07 00:11:09 +00:00
|
|
|
#include "qfiledialog.h"
|
2025-01-28 20:27:33 +00:00
|
|
|
#include "qitemselectionmodel.h"
|
2025-01-20 10:25:04 +00:00
|
|
|
#include "qobject.h"
|
2025-02-04 20:32:54 +00:00
|
|
|
#include "qsysinfo.h"
|
2024-12-01 23:14:42 +00:00
|
|
|
|
2025-02-05 22:57:02 +00:00
|
|
|
bool simulationPlaying = false;
|
|
|
|
|
2024-11-25 21:20:39 +00:00
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
|
|
: QMainWindow(parent)
|
|
|
|
, ui(new Ui::MainWindow)
|
|
|
|
{
|
2025-02-04 20:32:54 +00:00
|
|
|
dataModel->Init();
|
|
|
|
|
2024-11-25 21:20:39 +00:00
|
|
|
ui->setupUi(this);
|
2024-12-01 12:08:45 +00:00
|
|
|
timer.start(33, this);
|
|
|
|
setMouseTracking(true);
|
2024-12-02 10:01:51 +00:00
|
|
|
|
2025-02-07 00:11:09 +00:00
|
|
|
ConnectSelectionChangeHandler();
|
2025-01-28 20:27:33 +00:00
|
|
|
|
2025-02-23 15:22:17 +00:00
|
|
|
connect(ui->actionToolSelect, &QAction::triggered, this, [&]() { selectedTool = SelectedTool::SELECT; updateToolbars(); });
|
|
|
|
connect(ui->actionToolMove, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::MOVE : SelectedTool::SELECT; updateToolbars(); });
|
|
|
|
connect(ui->actionToolScale, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::SCALE : SelectedTool::SELECT; updateToolbars(); });
|
|
|
|
connect(ui->actionToolRotate, &QAction::triggered, this, [&](bool state) { selectedTool = state ? SelectedTool::ROTATE : SelectedTool::SELECT; updateToolbars(); });
|
2025-02-02 23:23:25 +00:00
|
|
|
ui->actionToolSelect->setChecked(true);
|
2025-02-23 15:22:17 +00:00
|
|
|
selectedTool = SelectedTool::SELECT;
|
|
|
|
|
|
|
|
connect(ui->actionGridSnap1, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_1_STUD; updateToolbars(); });
|
|
|
|
connect(ui->actionGridSnap05, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_05_STUDS; updateToolbars(); });
|
|
|
|
connect(ui->actionGridSnapOff, &QAction::triggered, this, [&]() { snappingMode = GridSnappingMode::SNAP_OFF; updateToolbars(); });
|
|
|
|
ui->actionGridSnap1->setChecked(true);
|
|
|
|
snappingMode = GridSnappingMode::SNAP_1_STUD;
|
2025-02-05 22:57:02 +00:00
|
|
|
|
|
|
|
connect(ui->actionToggleSimulation, &QAction::triggered, this, [&]() {
|
|
|
|
simulationPlaying = !simulationPlaying;
|
|
|
|
if (simulationPlaying) {
|
|
|
|
ui->actionToggleSimulation->setText("Pause simulation");
|
|
|
|
ui->actionToggleSimulation->setToolTip("Pause the simulation");
|
|
|
|
ui->actionToggleSimulation->setIcon(QIcon::fromTheme("media-playback-pause"));
|
|
|
|
} else {
|
|
|
|
ui->actionToggleSimulation->setText("Resume simulation");
|
|
|
|
ui->actionToggleSimulation->setToolTip("Resume the simulation");
|
|
|
|
ui->actionToggleSimulation->setIcon(QIcon::fromTheme("media-playback-start"));
|
|
|
|
}
|
|
|
|
});
|
2025-02-06 17:58:00 +00:00
|
|
|
|
|
|
|
connect(ui->actionSave, &QAction::triggered, this, [&]() {
|
2025-02-07 00:11:09 +00:00
|
|
|
std::optional<std::string> path;
|
|
|
|
if (!dataModel->HasFile())
|
|
|
|
path = QFileDialog::getSaveFileName(this, QString::fromStdString("Save " + dataModel->name), "", "*.obl").toStdString();
|
|
|
|
if (path == "") return;
|
|
|
|
|
|
|
|
dataModel->SaveToFile(path);
|
|
|
|
});
|
2025-02-06 17:58:00 +00:00
|
|
|
|
2025-02-07 00:11:09 +00:00
|
|
|
connect(ui->actionOpen, &QAction::triggered, this, [&]() {
|
|
|
|
std::string path = QFileDialog::getOpenFileName(this, "Load file", "", "*.obl").toStdString();
|
|
|
|
if (path == "") return;
|
|
|
|
std::shared_ptr<DataModel> newModel = DataModel::LoadFromFile(path);
|
|
|
|
dataModel = newModel;
|
|
|
|
delete ui->explorerView->selectionModel();
|
|
|
|
ui->explorerView->reset();
|
|
|
|
ui->explorerView->setModel(new ExplorerModel(dataModel));
|
|
|
|
ConnectSelectionChangeHandler();
|
2025-02-06 17:58:00 +00:00
|
|
|
});
|
2025-02-02 23:23:25 +00:00
|
|
|
|
2025-02-27 21:22:59 +00:00
|
|
|
// Update handles
|
2025-02-18 21:50:16 +00:00
|
|
|
addSelectionListener([&](auto oldSelection, auto newSelection, bool fromExplorer) {
|
2025-02-23 15:45:16 +00:00
|
|
|
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);
|
2025-02-18 21:50:16 +00:00
|
|
|
});
|
|
|
|
|
2025-02-27 21:22:59 +00:00
|
|
|
// 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());
|
|
|
|
});
|
|
|
|
|
2025-01-23 10:25:07 +00:00
|
|
|
// ui->explorerView->Init(ui);
|
2025-01-17 23:13:42 +00:00
|
|
|
|
2024-12-02 10:01:51 +00:00
|
|
|
simulationInit();
|
|
|
|
|
|
|
|
// Baseplate
|
2025-02-04 20:44:54 +00:00
|
|
|
workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
2024-12-02 10:01:51 +00:00
|
|
|
.position = glm::vec3(0, -5, 0),
|
|
|
|
.rotation = glm::vec3(0),
|
2025-02-09 10:35:19 +00:00
|
|
|
.size = glm::vec3(512, 1.2, 512),
|
2025-02-08 22:42:46 +00:00
|
|
|
.color = glm::vec3(0.388235, 0.372549, 0.384314),
|
2024-12-02 10:01:51 +00:00
|
|
|
.anchored = true,
|
2025-01-17 08:24:18 +00:00
|
|
|
}));
|
2025-01-20 10:25:04 +00:00
|
|
|
ui->mainWidget->lastPart->name = "Baseplate";
|
2025-01-17 08:24:18 +00:00
|
|
|
syncPartPhysics(ui->mainWidget->lastPart);
|
2024-12-02 10:01:51 +00:00
|
|
|
|
2025-02-04 20:44:54 +00:00
|
|
|
workspace()->AddChild(ui->mainWidget->lastPart = Part::New({
|
2024-12-02 10:01:51 +00:00
|
|
|
.position = glm::vec3(0),
|
2025-02-27 21:22:59 +00:00
|
|
|
.rotation = glm::vec3(0.5, 2, 1),
|
2025-02-09 10:35:19 +00:00
|
|
|
.size = glm::vec3(4, 1.2, 2),
|
2025-02-08 22:42:46 +00:00
|
|
|
.color = glm::vec3(0.639216f, 0.635294f, 0.647059f),
|
2025-01-17 08:24:18 +00:00
|
|
|
}));
|
|
|
|
syncPartPhysics(ui->mainWidget->lastPart);
|
2024-12-01 12:08:45 +00:00
|
|
|
}
|
|
|
|
|
2025-02-07 00:11:09 +00:00
|
|
|
void MainWindow::ConnectSelectionChangeHandler() {
|
2025-02-27 21:22:59 +00:00
|
|
|
// connect(ui->explorerView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&](const QItemSelection &selected, const QItemSelection &deselected) {
|
|
|
|
// if (selected.count() == 0) return;
|
2025-02-07 00:11:09 +00:00
|
|
|
|
2025-02-27 21:22:59 +00:00
|
|
|
// std::optional<InstanceRef> inst = selected.count() == 0 ? std::nullopt
|
|
|
|
// : std::make_optional(((Instance*)selected.indexes()[0].internalPointer())->shared_from_this());
|
2025-02-07 00:11:09 +00:00
|
|
|
|
2025-02-27 21:22:59 +00:00
|
|
|
// ui->propertiesView->setSelected(inst);
|
|
|
|
// });
|
2025-02-07 00:11:09 +00:00
|
|
|
}
|
|
|
|
|
2024-12-02 10:01:51 +00:00
|
|
|
static std::chrono::time_point lastTime = std::chrono::steady_clock::now();
|
2024-12-01 12:08:45 +00:00
|
|
|
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();
|
|
|
|
|
2025-02-05 22:57:02 +00:00
|
|
|
if (simulationPlaying)
|
|
|
|
physicsStep(deltaTime);
|
2024-12-01 12:08:45 +00:00
|
|
|
ui->mainWidget->update();
|
2024-12-02 10:01:51 +00:00
|
|
|
ui->mainWidget->updateCycle();
|
2024-11-25 21:20:39 +00:00
|
|
|
}
|
|
|
|
|
2025-02-23 15:22:17 +00:00
|
|
|
void MainWindow::updateToolbars() {
|
2025-02-02 23:23:25 +00:00
|
|
|
ui->actionToolSelect->setChecked(selectedTool == SelectedTool::SELECT);
|
|
|
|
ui->actionToolMove->setChecked(selectedTool == SelectedTool::MOVE);
|
|
|
|
ui->actionToolScale->setChecked(selectedTool == SelectedTool::SCALE);
|
|
|
|
ui->actionToolRotate->setChecked(selectedTool == SelectedTool::ROTATE);
|
2025-02-18 21:50:16 +00:00
|
|
|
|
2025-02-23 15:22:17 +00:00
|
|
|
ui->actionGridSnap1->setChecked(snappingMode == GridSnappingMode::SNAP_1_STUD);
|
|
|
|
ui->actionGridSnap05->setChecked(snappingMode == GridSnappingMode::SNAP_05_STUDS);
|
|
|
|
ui->actionGridSnapOff->setChecked(snappingMode == GridSnappingMode::SNAP_OFF);
|
|
|
|
|
2025-02-27 21:22:59 +00:00
|
|
|
// editorToolHandles->worldMode = false;
|
2025-02-18 21:50:16 +00:00
|
|
|
if (selectedTool == SelectedTool::MOVE) editorToolHandles->worldMode = true;
|
|
|
|
if (selectedTool == SelectedTool::SCALE) editorToolHandles->worldMode = false;
|
2025-02-23 15:45:16 +00:00
|
|
|
editorToolHandles->active = selectedTool != SelectedTool::SELECT;
|
2025-02-02 23:23:25 +00:00
|
|
|
}
|
|
|
|
|
2024-11-25 21:20:39 +00:00
|
|
|
MainWindow::~MainWindow()
|
|
|
|
{
|
|
|
|
delete ui;
|
2024-12-01 11:26:14 +00:00
|
|
|
}
|