Add inspector
This commit is contained in:
parent
7f9f9702fc
commit
815910ac90
12 changed files with 341 additions and 3 deletions
|
@ -1,6 +1,9 @@
|
||||||
set(INCLUDE_FILES
|
set(INCLUDE_FILES
|
||||||
include/renderwindow.h
|
include/renderwindow.h
|
||||||
include/coloredit.h)
|
include/coloredit.h
|
||||||
|
include/context.h
|
||||||
|
include/vec3edit.h
|
||||||
|
include/collapsesection.h)
|
||||||
|
|
||||||
qt5_wrap_cpp(EDITOR_SRC ${INCLUDE_FILES})
|
qt5_wrap_cpp(EDITOR_SRC ${INCLUDE_FILES})
|
||||||
|
|
||||||
|
@ -9,6 +12,8 @@ add_library(EditorCommon
|
||||||
src/renderwindow.cpp
|
src/renderwindow.cpp
|
||||||
src/editorstyle.cpp
|
src/editorstyle.cpp
|
||||||
src/coloredit.cpp
|
src/coloredit.cpp
|
||||||
|
src/vec3edit.cpp
|
||||||
|
src/collapsesection.cpp
|
||||||
${EDITOR_SRC})
|
${EDITOR_SRC})
|
||||||
target_include_directories(EditorCommon PUBLIC include)
|
target_include_directories(EditorCommon PUBLIC include)
|
||||||
target_link_libraries(EditorCommon PRIVATE Engine Qt5::Widgets)
|
target_link_libraries(EditorCommon PRIVATE Engine Qt5::Widgets)
|
||||||
|
|
28
tools/common/include/collapsesection.h
Normal file
28
tools/common/include/collapsesection.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class CollapseSection : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
CollapseSection(QString label, bool closable = false);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void closeRequested();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintEvent(QPaintEvent* event) override;
|
||||||
|
void mouseMoveEvent(QMouseEvent* event) override;
|
||||||
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString label;
|
||||||
|
|
||||||
|
bool closable;
|
||||||
|
QRect closeButtonRect;
|
||||||
|
bool closeButtonHovered = false;
|
||||||
|
bool collapsed = false;
|
||||||
|
|
||||||
|
QWidget* wrapper;
|
||||||
|
QLayout* layout;
|
||||||
|
};
|
|
@ -1,11 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
class Renderer;
|
class Renderer;
|
||||||
|
|
||||||
using EntityID = uint64_t;
|
using EntityID = uint64_t;
|
||||||
|
|
||||||
struct Context {
|
class Context : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
Renderer* renderer;
|
Renderer* renderer;
|
||||||
|
|
||||||
std::vector<EntityID> selectedEntities;
|
std::vector<EntityID> selectedEntities;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void selectionChanged();
|
||||||
};
|
};
|
||||||
|
|
23
tools/common/include/vec3edit.h
Normal file
23
tools/common/include/vec3edit.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
class Vector3Edit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit Vector3Edit(glm::vec3& vec, QWidget* parent = nullptr);
|
||||||
|
~Vector3Edit();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void onValueChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct {
|
||||||
|
QDoubleSpinBox *x, *y, *z;
|
||||||
|
} spinBoxes;
|
||||||
|
|
||||||
|
glm::vec3& vec;
|
||||||
|
QTimer* updateTimer;
|
||||||
|
};
|
75
tools/common/src/collapsesection.cpp
Normal file
75
tools/common/src/collapsesection.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#include "collapsesection.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QStyleOption>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
CollapseSection::CollapseSection(QString label, bool closable) : label(label), closable(closable) {
|
||||||
|
setContentsMargins(0, 25, 0, 0);
|
||||||
|
setMouseTracking(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapseSection::paintEvent(QPaintEvent* event) {
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setPen(QColor(75, 75, 80));
|
||||||
|
painter.setBrush(QColor(50, 50, 55));
|
||||||
|
|
||||||
|
QRect r = event->rect().adjusted(1, 2, -1, 0);
|
||||||
|
r.setHeight(25);
|
||||||
|
|
||||||
|
painter.drawRect(r);
|
||||||
|
|
||||||
|
painter.setPen(Qt::white);
|
||||||
|
painter.drawText(event->rect().adjusted(6, 5, 0, 0), label);
|
||||||
|
|
||||||
|
if(closable) {
|
||||||
|
QStyleOption option;
|
||||||
|
option.rect.adjust(event->rect().width() - 20, 7, 0, 0);
|
||||||
|
option.rect.setHeight(16);
|
||||||
|
option.rect.setWidth(16);
|
||||||
|
option.state = QStyle::State_Active|QStyle::State_Enabled|QStyle::State_AutoRaise;
|
||||||
|
|
||||||
|
if(closeButtonHovered)
|
||||||
|
option.state |= QStyle::State_Raised | QStyle::State_MouseOver;
|
||||||
|
|
||||||
|
QApplication::style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &option, &painter, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapseSection::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
if(closable) {
|
||||||
|
QRect r(width() - 20, 0, width(), 25); // close button
|
||||||
|
|
||||||
|
if(r.contains(mapFromGlobal(QCursor::pos())))
|
||||||
|
closeButtonHovered = true;
|
||||||
|
else
|
||||||
|
closeButtonHovered = false;
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CollapseSection::mousePressEvent(QMouseEvent* event) {
|
||||||
|
QRect r(0, 0, width() - 20, 30); // header
|
||||||
|
|
||||||
|
if(r.contains(mapFromGlobal(QCursor::pos()))) {
|
||||||
|
if(!collapsed) {
|
||||||
|
setFixedHeight(30);
|
||||||
|
collapsed = true;
|
||||||
|
} else {
|
||||||
|
setFixedHeight(QWIDGETSIZE_MAX);
|
||||||
|
collapsed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(closable) {
|
||||||
|
QRect r(width() - 20, 0, width(), 25); // close button
|
||||||
|
|
||||||
|
if(r.contains(mapFromGlobal(QCursor::pos())))
|
||||||
|
emit closeRequested();
|
||||||
|
}
|
||||||
|
}
|
58
tools/common/src/vec3edit.cpp
Normal file
58
tools/common/src/vec3edit.cpp
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include "vec3edit.h"
|
||||||
|
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
Vector3Edit::Vector3Edit(glm::vec3& vec, QWidget* parent) : QWidget(parent), vec(vec) {
|
||||||
|
QHBoxLayout* itemsLayout = new QHBoxLayout(this);
|
||||||
|
|
||||||
|
spinBoxes.x = new QDoubleSpinBox();
|
||||||
|
spinBoxes.y = new QDoubleSpinBox();
|
||||||
|
spinBoxes.z = new QDoubleSpinBox();
|
||||||
|
|
||||||
|
spinBoxes.x->setMinimum(-10000.0);
|
||||||
|
spinBoxes.x->setMaximum(10000.0);
|
||||||
|
|
||||||
|
spinBoxes.y->setMinimum(-10000.0);
|
||||||
|
spinBoxes.y->setMaximum(10000.0);
|
||||||
|
|
||||||
|
spinBoxes.z->setMinimum(-10000.0);
|
||||||
|
spinBoxes.z->setMaximum(10000.0);
|
||||||
|
|
||||||
|
itemsLayout->addWidget(spinBoxes.x);
|
||||||
|
itemsLayout->addWidget(spinBoxes.y);
|
||||||
|
itemsLayout->addWidget(spinBoxes.z);
|
||||||
|
|
||||||
|
spinBoxes.x->setValue(vec.x);
|
||||||
|
spinBoxes.y->setValue(vec.y);
|
||||||
|
spinBoxes.z->setValue(vec.z);
|
||||||
|
|
||||||
|
connect(spinBoxes.x, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) {
|
||||||
|
vec.x = d;
|
||||||
|
emit onValueChanged();
|
||||||
|
});
|
||||||
|
connect(spinBoxes.y, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) {
|
||||||
|
vec.y = d;
|
||||||
|
emit onValueChanged();
|
||||||
|
});
|
||||||
|
connect(spinBoxes.z, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, &vec](double d) {
|
||||||
|
vec.z = d;
|
||||||
|
emit onValueChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: find a better way to do this
|
||||||
|
updateTimer = new QTimer();
|
||||||
|
connect(updateTimer, &QTimer::timeout, [this, &vec]() {
|
||||||
|
if (vec.x != spinBoxes.x->value() || vec.y != spinBoxes.y->value() || vec.z != spinBoxes.z->value()) {
|
||||||
|
spinBoxes.x->setValue(vec.x);
|
||||||
|
spinBoxes.y->setValue(vec.y);
|
||||||
|
spinBoxes.z->setValue(vec.z);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateTimer->start(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3Edit::~Vector3Edit() {
|
||||||
|
updateTimer->stop();
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
set(INCLUDE_FILES
|
set(INCLUDE_FILES
|
||||||
include/mainwindow.h
|
include/mainwindow.h
|
||||||
include/hierarchy.h)
|
include/hierarchy.h
|
||||||
|
include/inspector.h)
|
||||||
|
|
||||||
qt5_wrap_cpp(EDITOR_SRC ${INCLUDE_FILES})
|
qt5_wrap_cpp(EDITOR_SRC ${INCLUDE_FILES})
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ add_executable(LevelEditor
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/mainwindow.cpp
|
src/mainwindow.cpp
|
||||||
src/hierarchy.cpp
|
src/hierarchy.cpp
|
||||||
|
src/inspector.cpp
|
||||||
${EDITOR_SRC})
|
${EDITOR_SRC})
|
||||||
target_include_directories(LevelEditor PRIVATE include)
|
target_include_directories(LevelEditor PRIVATE include)
|
||||||
target_link_libraries(LevelEditor Qt5::Widgets Engine ToolWindowManager EditorCommon)
|
target_link_libraries(LevelEditor Qt5::Widgets Engine ToolWindowManager EditorCommon)
|
||||||
|
|
28
tools/leveleditor/include/inspector.h
Normal file
28
tools/leveleditor/include/inspector.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
struct Context;
|
||||||
|
struct InfoComponent;
|
||||||
|
struct TransformComponent;
|
||||||
|
struct MeshComponent;
|
||||||
|
|
||||||
|
class Inspector : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
Inspector(Context& context, QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void rebuild();
|
||||||
|
|
||||||
|
void addInfoInspector(InfoComponent* info);
|
||||||
|
void addTransformInspector(TransformComponent* transform);
|
||||||
|
void addMeshInspector(MeshComponent* mesh);
|
||||||
|
|
||||||
|
QVBoxLayout* layout = nullptr;
|
||||||
|
|
||||||
|
QList<QWidget*> sections;
|
||||||
|
|
||||||
|
Context& context;
|
||||||
|
};
|
|
@ -13,6 +13,7 @@ public:
|
||||||
private:
|
private:
|
||||||
void addSceneView();
|
void addSceneView();
|
||||||
void addHierarchy();
|
void addHierarchy();
|
||||||
|
void addInspector();
|
||||||
|
|
||||||
Context& context;
|
Context& context;
|
||||||
ToolWindowManager* manager = nullptr;
|
ToolWindowManager* manager = nullptr;
|
||||||
|
|
|
@ -24,6 +24,8 @@ Hierarchy::Hierarchy(Context& context, QWidget* parent) : QWidget(parent), conte
|
||||||
|
|
||||||
context.selectedEntities.push_back(entity);
|
context.selectedEntities.push_back(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit context.selectionChanged();
|
||||||
});
|
});
|
||||||
|
|
||||||
listModel = new QStringListModel();
|
listModel = new QStringListModel();
|
||||||
|
|
96
tools/leveleditor/src/inspector.cpp
Normal file
96
tools/leveleditor/src/inspector.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#include "inspector.h"
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
#include "context.h"
|
||||||
|
#include "ecs.h"
|
||||||
|
#include "worldmanager.h"
|
||||||
|
#include "vec3edit.h"
|
||||||
|
#include "collapsesection.h"
|
||||||
|
|
||||||
|
Inspector::Inspector(Context& context, QWidget* parent) : QWidget(parent), context(context) {
|
||||||
|
setWindowTitle("Inspector");
|
||||||
|
setWindowIcon(QIcon::fromTheme("edit-cut"));
|
||||||
|
|
||||||
|
layout = new QVBoxLayout();
|
||||||
|
layout->setAlignment(Qt::AlignTop);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
rebuild();
|
||||||
|
|
||||||
|
connect(&context, &Context::selectionChanged, this, &Inspector::rebuild);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inspector::rebuild() {
|
||||||
|
for(auto section : sections) {
|
||||||
|
layout->removeWidget(section);
|
||||||
|
delete section;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.clear();
|
||||||
|
|
||||||
|
if(context.selectedEntities.size() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto& entity = context.selectedEntities[0];
|
||||||
|
|
||||||
|
InfoComponent* info = ECS::getComponent<InfoComponent>(entity);
|
||||||
|
if(info)
|
||||||
|
addInfoInspector(info);
|
||||||
|
|
||||||
|
TransformComponent* transform = ECS::getComponent<TransformComponent>(entity);
|
||||||
|
if(transform)
|
||||||
|
addTransformInspector(transform);
|
||||||
|
|
||||||
|
MeshComponent* mesh = ECS::getComponent<MeshComponent>(entity);
|
||||||
|
if(mesh)
|
||||||
|
addMeshInspector(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inspector::addInfoInspector(InfoComponent* info) {
|
||||||
|
CollapseSection* section = new CollapseSection("Info");
|
||||||
|
layout->addWidget(section);
|
||||||
|
sections.push_back(section);
|
||||||
|
|
||||||
|
QGridLayout* layout = new QGridLayout();
|
||||||
|
section->setLayout(layout);
|
||||||
|
|
||||||
|
QLabel* nameLabel = new QLabel("Name");
|
||||||
|
layout->addWidget(nameLabel);
|
||||||
|
|
||||||
|
QLineEdit* nameEdit = new QLineEdit();
|
||||||
|
nameEdit->setText(info->name.c_str());
|
||||||
|
|
||||||
|
connect(nameEdit, &QLineEdit::editingFinished, [info, nameEdit] {
|
||||||
|
info->name = nameEdit->text().toStdString();
|
||||||
|
});
|
||||||
|
layout->addWidget(nameEdit, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inspector::addTransformInspector(TransformComponent* transform) {
|
||||||
|
CollapseSection* section = new CollapseSection("Transform");
|
||||||
|
layout->addWidget(section);
|
||||||
|
sections.push_back(section);
|
||||||
|
|
||||||
|
QGridLayout* layout = new QGridLayout();
|
||||||
|
section->setLayout(layout);
|
||||||
|
|
||||||
|
QLabel* positionLabel = new QLabel("Position");
|
||||||
|
layout->addWidget(positionLabel);
|
||||||
|
|
||||||
|
Vector3Edit* positionEdit = new Vector3Edit(transform->position);
|
||||||
|
layout->addWidget(positionEdit, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inspector::addMeshInspector(MeshComponent* mesh) {
|
||||||
|
CollapseSection* section = new CollapseSection("Mesh", true);
|
||||||
|
layout->addWidget(section);
|
||||||
|
sections.push_back(section);
|
||||||
|
|
||||||
|
QGridLayout* layout = new QGridLayout();
|
||||||
|
section->setLayout(layout);
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
#include "renderwindow.h"
|
#include "renderwindow.h"
|
||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "hierarchy.h"
|
#include "hierarchy.h"
|
||||||
|
#include "inspector.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(Context& context) : context(context) {
|
MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
setWindowTitle("Level Editor");
|
setWindowTitle("Level Editor");
|
||||||
|
@ -122,6 +123,11 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
connect(addHierarchy, &QAction::triggered, this, &MainWindow::addHierarchy);
|
connect(addHierarchy, &QAction::triggered, this, &MainWindow::addHierarchy);
|
||||||
addHierarchy->setIcon(QIcon::fromTheme("view-sort-ascending"));
|
addHierarchy->setIcon(QIcon::fromTheme("view-sort-ascending"));
|
||||||
newViewMenu->addAction(addHierarchy);
|
newViewMenu->addAction(addHierarchy);
|
||||||
|
|
||||||
|
QAction* addInspector = new QAction("Inspector");
|
||||||
|
connect(addInspector, &QAction::triggered, this, &MainWindow::addInspector);
|
||||||
|
addInspector->setIcon(QIcon::fromTheme("edit-cut"));
|
||||||
|
newViewMenu->addAction(addInspector);
|
||||||
}
|
}
|
||||||
|
|
||||||
mainMenuBar->addSeparator();
|
mainMenuBar->addSeparator();
|
||||||
|
@ -138,6 +144,7 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
||||||
|
|
||||||
addSceneView();
|
addSceneView();
|
||||||
addHierarchy();
|
addHierarchy();
|
||||||
|
addInspector();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::addSceneView() {
|
void MainWindow::addSceneView() {
|
||||||
|
@ -157,3 +164,9 @@ void MainWindow::addHierarchy() {
|
||||||
manager->addToolWindow(hierarchy, ToolWindowManager::AreaReference(ToolWindowManager::EmptySpace));
|
manager->addToolWindow(hierarchy, ToolWindowManager::AreaReference(ToolWindowManager::EmptySpace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::addInspector() {
|
||||||
|
Inspector* inspector = new Inspector(context);
|
||||||
|
|
||||||
|
manager->addToolWindow(inspector, ToolWindowManager::AreaReference(ToolWindowManager::EmptySpace));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue