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
|
||||
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})
|
||||
|
||||
|
@ -9,6 +12,8 @@ add_library(EditorCommon
|
|||
src/renderwindow.cpp
|
||||
src/editorstyle.cpp
|
||||
src/coloredit.cpp
|
||||
src/vec3edit.cpp
|
||||
src/collapsesection.cpp
|
||||
${EDITOR_SRC})
|
||||
target_include_directories(EditorCommon PUBLIC include)
|
||||
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
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Renderer;
|
||||
|
||||
using EntityID = uint64_t;
|
||||
|
||||
struct Context {
|
||||
class Context : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Renderer* renderer;
|
||||
|
||||
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
|
||||
include/mainwindow.h
|
||||
include/hierarchy.h)
|
||||
include/hierarchy.h
|
||||
include/inspector.h)
|
||||
|
||||
qt5_wrap_cpp(EDITOR_SRC ${INCLUDE_FILES})
|
||||
|
||||
|
@ -8,6 +9,7 @@ add_executable(LevelEditor
|
|||
src/main.cpp
|
||||
src/mainwindow.cpp
|
||||
src/hierarchy.cpp
|
||||
src/inspector.cpp
|
||||
${EDITOR_SRC})
|
||||
target_include_directories(LevelEditor PRIVATE include)
|
||||
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:
|
||||
void addSceneView();
|
||||
void addHierarchy();
|
||||
void addInspector();
|
||||
|
||||
Context& context;
|
||||
ToolWindowManager* manager = nullptr;
|
||||
|
|
|
@ -24,6 +24,8 @@ Hierarchy::Hierarchy(Context& context, QWidget* parent) : QWidget(parent), conte
|
|||
|
||||
context.selectedEntities.push_back(entity);
|
||||
}
|
||||
|
||||
emit context.selectionChanged();
|
||||
});
|
||||
|
||||
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 "renderer.h"
|
||||
#include "hierarchy.h"
|
||||
#include "inspector.h"
|
||||
|
||||
MainWindow::MainWindow(Context& context) : context(context) {
|
||||
setWindowTitle("Level Editor");
|
||||
|
@ -122,6 +123,11 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
|||
connect(addHierarchy, &QAction::triggered, this, &MainWindow::addHierarchy);
|
||||
addHierarchy->setIcon(QIcon::fromTheme("view-sort-ascending"));
|
||||
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();
|
||||
|
@ -138,6 +144,7 @@ MainWindow::MainWindow(Context& context) : context(context) {
|
|||
|
||||
addSceneView();
|
||||
addHierarchy();
|
||||
addInspector();
|
||||
}
|
||||
|
||||
void MainWindow::addSceneView() {
|
||||
|
@ -157,3 +164,9 @@ void MainWindow::addHierarchy() {
|
|||
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