Merge pull request 'Supporting setting panel layout' (#7) from issue-5/support-default-editor-panel-layout-and-locked-panels into main
Reviewed-on: #7
This commit was merged in pull request #7.
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include "panels/asset_browser_panel.hpp"
|
#include "panels/asset_browser_panel.hpp"
|
||||||
#include "panels/inspector_panel.hpp"
|
#include "panels/inspector_panel.hpp"
|
||||||
#include "panels/scene_hierarchy_panel.hpp"
|
#include "panels/scene_hierarchy_panel.hpp"
|
||||||
|
#include "panels/viewport_panel.hpp"
|
||||||
|
|
||||||
class Editor : public sophia::Application {
|
class Editor : public sophia::Application {
|
||||||
public:
|
public:
|
||||||
@@ -17,6 +18,13 @@ class Editor : public sophia::Application {
|
|||||||
panels().emplace<SceneHierarchyPanel>();
|
panels().emplace<SceneHierarchyPanel>();
|
||||||
panels().emplace<InspectorPanel>();
|
panels().emplace<InspectorPanel>();
|
||||||
panels().emplace<AssetBrowserPanel>();
|
panels().emplace<AssetBrowserPanel>();
|
||||||
|
panels().emplace<ViewportPanel>();
|
||||||
|
|
||||||
|
panels().setDefaultLayout(
|
||||||
|
{.left = {"Scene Hierarchy"},
|
||||||
|
.right = {"Inspector", "Frame Stats", "PanelRegistry"},
|
||||||
|
.bottom = {"Asset Browser", "Console"},
|
||||||
|
.center = {"Viewport"}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdate(const sophia::FrameInfo& frameInfo) override {}
|
void onUpdate(const sophia::FrameInfo& frameInfo) override {}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
void AssetBrowserPanel::onUpdate(const sophia::FrameInfo&) {
|
void AssetBrowserPanel::onUpdate(const sophia::FrameInfo&) {
|
||||||
ImGui::Begin("Asset Browser");
|
|
||||||
|
|
||||||
ImGui::BeginChild("Folders", ImVec2(150, 0), true);
|
ImGui::BeginChild("Folders", ImVec2(150, 0), true);
|
||||||
for (int i = 0; i < static_cast<int>(folders.size()); i++) {
|
for (int i = 0; i < static_cast<int>(folders.size()); i++) {
|
||||||
if (ImGui::Selectable(folders[static_cast<size_t>(i)].name.c_str(),
|
if (ImGui::Selectable(folders[static_cast<size_t>(i)].name.c_str(),
|
||||||
@@ -22,6 +20,4 @@ void AssetBrowserPanel::onUpdate(const sophia::FrameInfo&) {
|
|||||||
ImGui::Selectable(file.c_str());
|
ImGui::Selectable(file.c_str());
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
class AssetBrowserPanel : public sophia::Panel {
|
class AssetBrowserPanel : public sophia::Panel {
|
||||||
public:
|
public:
|
||||||
AssetBrowserPanel() : Panel{"Asset Browser"} {}
|
AssetBrowserPanel() : Panel{{.name = "Asset Browser"}} {}
|
||||||
|
|
||||||
void onUpdate(const sophia::FrameInfo& frameInfo) override;
|
void onUpdate(const sophia::FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
void InspectorPanel::onUpdate(const sophia::FrameInfo&) {
|
void InspectorPanel::onUpdate(const sophia::FrameInfo&) {
|
||||||
ImGui::Begin("Inspector");
|
|
||||||
|
|
||||||
char nameBuf[128];
|
char nameBuf[128];
|
||||||
std::snprintf(nameBuf, sizeof(nameBuf), "%s", name.c_str());
|
std::snprintf(nameBuf, sizeof(nameBuf), "%s", name.c_str());
|
||||||
if (ImGui::InputText("Name", nameBuf, sizeof(nameBuf))) {
|
if (ImGui::InputText("Name", nameBuf, sizeof(nameBuf))) {
|
||||||
@@ -31,6 +29,4 @@ void InspectorPanel::onUpdate(const sophia::FrameInfo&) {
|
|||||||
if (ImGui::CollapsingHeader("Script", ImGuiTreeNodeFlags_DefaultOpen)) {
|
if (ImGui::CollapsingHeader("Script", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
ImGui::Text("%s", scriptName.c_str());
|
ImGui::Text("%s", scriptName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
class InspectorPanel : public sophia::Panel {
|
class InspectorPanel : public sophia::Panel {
|
||||||
public:
|
public:
|
||||||
InspectorPanel() : Panel{"Inspector"} {}
|
InspectorPanel() : Panel{{.name = "Inspector"}} {}
|
||||||
|
|
||||||
void onUpdate(const sophia::FrameInfo& frameInfo) override;
|
void onUpdate(const sophia::FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ void SceneHierarchyPanel::drawNode(const Node& node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SceneHierarchyPanel::onUpdate(const sophia::FrameInfo&) {
|
void SceneHierarchyPanel::onUpdate(const sophia::FrameInfo&) {
|
||||||
ImGui::Begin("Scene Hierarchy");
|
|
||||||
for (const Node& node : nodes) {
|
for (const Node& node : nodes) {
|
||||||
drawNode(node);
|
drawNode(node);
|
||||||
}
|
}
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
class SceneHierarchyPanel : public sophia::Panel {
|
class SceneHierarchyPanel : public sophia::Panel {
|
||||||
public:
|
public:
|
||||||
SceneHierarchyPanel() : Panel{"Scene Hierarchy"} {}
|
SceneHierarchyPanel() : Panel{{.name = "Scene Hierarchy", .locked = true}} {}
|
||||||
|
|
||||||
void onUpdate(const sophia::FrameInfo& frameInfo) override;
|
void onUpdate(const sophia::FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
#include "viewport_panel.hpp"
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
void ViewportPanel::onUpdate(const sophia::FrameInfo&) {
|
||||||
|
const struct {
|
||||||
|
const char* label;
|
||||||
|
GizmoMode mode;
|
||||||
|
} modes[] = {{"Move", GizmoMode::Move},
|
||||||
|
{"Rotate", GizmoMode::Rotate},
|
||||||
|
{"Scale", GizmoMode::Scale}};
|
||||||
|
|
||||||
|
for (const auto& entry : modes) {
|
||||||
|
if (ImGui::RadioButton(entry.label, gizmoMode == entry.mode)) {
|
||||||
|
gizmoMode = entry.mode;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
ImGui::Checkbox("Grid", &showGrid);
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
const ImVec2 origin = ImGui::GetCursorScreenPos();
|
||||||
|
const ImVec2 size = ImGui::GetContentRegionAvail();
|
||||||
|
const ImVec2 end(origin.x + size.x, origin.y + size.y);
|
||||||
|
|
||||||
|
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||||
|
drawList->AddRectFilled(origin, end, IM_COL32(24, 26, 32, 255));
|
||||||
|
|
||||||
|
if (showGrid) {
|
||||||
|
constexpr float GRID_STEP = 40.0f;
|
||||||
|
const ImU32 gridColor = IM_COL32(255, 255, 255, 18);
|
||||||
|
for (float x = GRID_STEP; x < size.x; x += GRID_STEP) {
|
||||||
|
drawList->AddLine(ImVec2(origin.x + x, origin.y),
|
||||||
|
ImVec2(origin.x + x, end.y), gridColor);
|
||||||
|
}
|
||||||
|
for (float y = GRID_STEP; y < size.y; y += GRID_STEP) {
|
||||||
|
drawList->AddLine(ImVec2(origin.x, origin.y + y),
|
||||||
|
ImVec2(end.x, origin.y + y), gridColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SetCursorScreenPos(ImVec2(origin.x + 8.0f, origin.y + 8.0f));
|
||||||
|
ImGui::TextDisabled("%.0f x %.0f", size.x, size.y);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sophia/frame_info.hpp>
|
||||||
|
#include <sophia/ui/panel.hpp>
|
||||||
|
|
||||||
|
class ViewportPanel : public sophia::Panel {
|
||||||
|
public:
|
||||||
|
ViewportPanel() : Panel{{.name = "Viewport"}} {}
|
||||||
|
|
||||||
|
void onUpdate(const sophia::FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class GizmoMode { Move, Rotate, Scale };
|
||||||
|
|
||||||
|
GizmoMode gizmoMode = GizmoMode::Move;
|
||||||
|
bool showGrid = true;
|
||||||
|
};
|
||||||
@@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
#include <any>
|
#include <any>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include <sophia/types.hpp>
|
#include <sophia/types.hpp>
|
||||||
#include <sophia/util/delegate.hpp>
|
#include <sophia/util/delegate.hpp>
|
||||||
#include <sophia/util/logger.hpp>
|
#include <sophia/util/logger.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#define BIT(x) (1 << (x))
|
#define BIT(x) (1 << (x))
|
||||||
|
|
||||||
@@ -116,7 +115,9 @@ class EventSystem {
|
|||||||
static_assert(std::is_base_of<Event, E>::value, "E must derive from Event");
|
static_assert(std::is_base_of<Event, E>::value, "E must derive from Event");
|
||||||
EventType eventType = GET_EVENT_TYPE(E);
|
EventType eventType = GET_EVENT_TYPE(E);
|
||||||
|
|
||||||
if (!this->eventDelegates.count(eventType)) { return; }
|
if (!this->eventDelegates.count(eventType)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
EventDelegate<E>& delegate =
|
EventDelegate<E>& delegate =
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
struct DockLayout {
|
||||||
|
float leftWidth = 0.2f;
|
||||||
|
float rightWidth = 0.25f;
|
||||||
|
float bottomHeight = 0.25f;
|
||||||
|
|
||||||
|
std::vector<std::string> left;
|
||||||
|
std::vector<std::string> right;
|
||||||
|
std::vector<std::string> bottom;
|
||||||
|
std::vector<std::string> center;
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return left.empty() && right.empty() && bottom.empty() && center.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <optional>
|
||||||
#include <sophia/frame_info.hpp>
|
#include <sophia/frame_info.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -8,28 +12,52 @@ namespace sophia {
|
|||||||
|
|
||||||
class Panel {
|
class Panel {
|
||||||
public:
|
public:
|
||||||
|
struct Config {
|
||||||
|
const std::string name;
|
||||||
|
|
||||||
|
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_None;
|
||||||
|
ImGuiDockNodeFlags dockNodeFlags = ImGuiDockNodeFlags_None;
|
||||||
|
|
||||||
|
bool locked = false;
|
||||||
|
bool closable = true;
|
||||||
|
|
||||||
|
glm::vec2 size{0.0f, 0.0f};
|
||||||
|
std::optional<glm::vec2> position;
|
||||||
|
|
||||||
|
ImGuiWindowFlags getWindowFlags() const;
|
||||||
|
ImGuiDockNodeFlags getDockNodeFlags() const;
|
||||||
|
bool hasCloseButton() const;
|
||||||
|
ImGuiCond getPlacementCond() const;
|
||||||
|
};
|
||||||
|
|
||||||
Panel(const Panel&) = delete;
|
Panel(const Panel&) = delete;
|
||||||
Panel& operator=(const Panel&) = delete;
|
Panel& operator=(const Panel&) = delete;
|
||||||
|
|
||||||
Panel(Panel&&) noexcept = default;
|
Panel(Panel&&) noexcept = default;
|
||||||
Panel& operator=(Panel&&) noexcept = default;
|
Panel& operator=(Panel&&) = delete;
|
||||||
|
|
||||||
explicit Panel(std::string name = {}) : name{std::move(name)} {}
|
explicit Panel(Config config) : config{std::move(config)} {}
|
||||||
virtual ~Panel() = default;
|
virtual ~Panel() = default;
|
||||||
|
|
||||||
virtual void onUpdate(const FrameInfo& frameInfo) = 0;
|
void draw(const FrameInfo& frameInfo);
|
||||||
|
|
||||||
const std::string& getName() const { return name; }
|
Config& getConfig() { return config; }
|
||||||
|
const Config& getConfig() const { return config; }
|
||||||
|
|
||||||
|
const std::string& getName() const { return config.name; }
|
||||||
|
bool isLocked() const { return config.locked; }
|
||||||
|
|
||||||
bool isVisible() const { return this->visible; }
|
bool isVisible() const { return this->visible; }
|
||||||
void setVisible(bool visible) { this->visible = visible; }
|
void setVisible(bool visible) { this->visible = visible; }
|
||||||
void toggleVisible() { this->visible = !this->visible; }
|
void toggleVisible() { this->visible = !this->visible; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void onUpdate(const FrameInfo& frameInfo) = 0;
|
||||||
|
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
Config config;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sophia/frame_info.hpp>
|
#include <sophia/frame_info.hpp>
|
||||||
#include <sophia/handles.hpp>
|
#include <sophia/handles.hpp>
|
||||||
|
#include <sophia/ui/dock_layout.hpp>
|
||||||
#include <sophia/ui/panel.hpp>
|
#include <sophia/ui/panel.hpp>
|
||||||
#include <sophia/util/assert.hpp>
|
#include <sophia/util/assert.hpp>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -94,6 +95,11 @@ class PanelRegistry {
|
|||||||
|
|
||||||
void update(const FrameInfo& frameInfo);
|
void update(const FrameInfo& frameInfo);
|
||||||
|
|
||||||
|
void setDefaultLayout(DockLayout layout) {
|
||||||
|
defaultLayout = std::move(layout);
|
||||||
|
}
|
||||||
|
const DockLayout& getDefaultLayout() const { return defaultLayout; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Slot {
|
struct Slot {
|
||||||
std::unique_ptr<Panel> panel;
|
std::unique_ptr<Panel> panel;
|
||||||
@@ -102,6 +108,7 @@ class PanelRegistry {
|
|||||||
|
|
||||||
std::vector<Slot> slots;
|
std::vector<Slot> slots;
|
||||||
std::vector<u32> freeList;
|
std::vector<u32> freeList;
|
||||||
|
DockLayout defaultLayout;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -12,9 +12,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <sophia/types.hpp>
|
#include <sophia/types.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace sophia::log {
|
namespace sophia::log {
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,16 @@ class Application::Impl {
|
|||||||
ImGuiRenderer imguiRenderer{window, device, renderContext.getImageFormat(),
|
ImGuiRenderer imguiRenderer{window, device, renderContext.getImageFormat(),
|
||||||
renderContext.getImageCount()};
|
renderContext.getImageCount()};
|
||||||
|
|
||||||
|
this->application.consoleCommandRegistry.registerCommand(
|
||||||
|
"reset_layout", "Restore the default panel layout",
|
||||||
|
[&imguiRenderer](const std::vector<std::string>&) {
|
||||||
|
imguiRenderer.resetLayout();
|
||||||
|
return std::string{"Layout reset"};
|
||||||
|
});
|
||||||
|
|
||||||
this->application.onCreate();
|
this->application.onCreate();
|
||||||
|
imguiRenderer.setDefaultLayout(
|
||||||
|
this->application.panelRegistry.getDefaultLayout());
|
||||||
|
|
||||||
auto startTime = std::chrono::high_resolution_clock::now();
|
auto startTime = std::chrono::high_resolution_clock::now();
|
||||||
auto currentTime = startTime;
|
auto currentTime = startTime;
|
||||||
|
|||||||
@@ -3,9 +3,21 @@
|
|||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
#include <imgui_impl_vulkan.h>
|
#include <imgui_impl_vulkan.h>
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr ImGuiDockNodeFlags DOCKSPACE_FLAGS =
|
||||||
|
ImGuiDockNodeFlags_PassthruCentralNode;
|
||||||
|
|
||||||
|
void dockAll(const std::vector<std::string>& windows, ImGuiID nodeId) {
|
||||||
|
for (const std::string& name : windows) {
|
||||||
|
ImGui::DockBuilderDockWindow(name.c_str(), nodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ImGuiRenderer::ImGuiRenderer(Window& window, Device& device,
|
ImGuiRenderer::ImGuiRenderer(Window& window, Device& device,
|
||||||
vk::Format colorAttachmentFormat,
|
vk::Format colorAttachmentFormat,
|
||||||
u32 minImageCount) {
|
u32 minImageCount) {
|
||||||
@@ -65,8 +77,59 @@ void ImGuiRenderer::beginFrame() {
|
|||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(),
|
ImGuiID dockspaceId = ImGui::DockSpaceOverViewport(
|
||||||
ImGuiDockNodeFlags_PassthruCentralNode);
|
0, ImGui::GetMainViewport(), DOCKSPACE_FLAGS);
|
||||||
|
applyLayoutIfNeeded(dockspaceId, DOCKSPACE_FLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiRenderer::setDefaultLayout(DockLayout layout) {
|
||||||
|
defaultLayout = std::move(layout);
|
||||||
|
seedIfUnsaved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGuiRenderer::resetLayout() { forceReset = true; }
|
||||||
|
|
||||||
|
void ImGuiRenderer::applyLayoutIfNeeded(ImGuiID dockspaceId,
|
||||||
|
ImGuiDockNodeFlags flags) {
|
||||||
|
if (defaultLayout.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool apply = forceReset;
|
||||||
|
if (seedIfUnsaved) {
|
||||||
|
// A layout restored from imgui.ini shows up as a split root node.
|
||||||
|
ImGuiDockNode* root = ImGui::DockBuilderGetNode(dockspaceId);
|
||||||
|
apply = apply || root == nullptr || !root->IsSplitNode();
|
||||||
|
seedIfUnsaved = false;
|
||||||
|
}
|
||||||
|
if (!apply) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
forceReset = false;
|
||||||
|
|
||||||
|
const ImVec2 size = ImGui::GetMainViewport()->Size;
|
||||||
|
|
||||||
|
ImGui::DockBuilderRemoveNode(dockspaceId);
|
||||||
|
ImGui::DockBuilderAddNode(dockspaceId, flags | ImGuiDockNodeFlags_DockSpace);
|
||||||
|
ImGui::DockBuilderSetNodeSize(dockspaceId, size);
|
||||||
|
|
||||||
|
ImGuiID center = dockspaceId;
|
||||||
|
const ImGuiID left = ImGui::DockBuilderSplitNode(
|
||||||
|
center, ImGuiDir_Left, defaultLayout.leftWidth, nullptr, ¢er);
|
||||||
|
// The right split is taken from what's left after the left split.
|
||||||
|
const float rightRatio =
|
||||||
|
defaultLayout.rightWidth / (1.0f - defaultLayout.leftWidth);
|
||||||
|
const ImGuiID right = ImGui::DockBuilderSplitNode(
|
||||||
|
center, ImGuiDir_Right, rightRatio, nullptr, ¢er);
|
||||||
|
const ImGuiID bottom = ImGui::DockBuilderSplitNode(
|
||||||
|
center, ImGuiDir_Down, defaultLayout.bottomHeight, nullptr, ¢er);
|
||||||
|
|
||||||
|
dockAll(defaultLayout.left, left);
|
||||||
|
dockAll(defaultLayout.right, right);
|
||||||
|
dockAll(defaultLayout.bottom, bottom);
|
||||||
|
dockAll(defaultLayout.center, center);
|
||||||
|
|
||||||
|
ImGui::DockBuilderFinish(dockspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiRenderer::endFrame(vk::CommandBuffer commandBuffer) {
|
void ImGuiRenderer::endFrame(vk::CommandBuffer commandBuffer) {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
#include <sophia/types.hpp>
|
#include <sophia/types.hpp>
|
||||||
|
#include <sophia/ui/dock_layout.hpp>
|
||||||
|
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
#include "window.hpp"
|
#include "window.hpp"
|
||||||
@@ -18,6 +21,16 @@ class ImGuiRenderer {
|
|||||||
|
|
||||||
void beginFrame();
|
void beginFrame();
|
||||||
void endFrame(vk::CommandBuffer commandBuffer);
|
void endFrame(vk::CommandBuffer commandBuffer);
|
||||||
|
|
||||||
|
void setDefaultLayout(DockLayout layout);
|
||||||
|
void resetLayout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void applyLayoutIfNeeded(ImGuiID dockspaceId, ImGuiDockNodeFlags flags);
|
||||||
|
|
||||||
|
DockLayout defaultLayout;
|
||||||
|
bool seedIfUnsaved = false;
|
||||||
|
bool forceReset = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
#include <sophia/ui/panel.hpp>
|
||||||
|
|
||||||
|
namespace sophia {
|
||||||
|
|
||||||
|
ImGuiWindowFlags Panel::Config::getWindowFlags() const {
|
||||||
|
ImGuiWindowFlags flags = windowFlags;
|
||||||
|
if (locked) {
|
||||||
|
flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_NoCollapse;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiDockNodeFlags Panel::Config::getDockNodeFlags() const {
|
||||||
|
ImGuiDockNodeFlags flags = dockNodeFlags;
|
||||||
|
if (locked) {
|
||||||
|
flags |= static_cast<int>(ImGuiDockNodeFlags_NoUndocking) |
|
||||||
|
static_cast<int>(ImGuiDockNodeFlags_NoResize) |
|
||||||
|
static_cast<int>(ImGuiDockNodeFlags_NoCloseButton) |
|
||||||
|
static_cast<int>(ImGuiDockNodeFlags_NoDockingOverMe) |
|
||||||
|
static_cast<int>(ImGuiDockNodeFlags_NoDockingSplit);
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Panel::Config::hasCloseButton() const { return closable && !locked; }
|
||||||
|
|
||||||
|
ImGuiCond Panel::Config::getPlacementCond() const {
|
||||||
|
return locked ? ImGuiCond_Always : ImGuiCond_FirstUseEver;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Panel::draw(const FrameInfo& frameInfo) {
|
||||||
|
ImGuiWindowClass windowClass;
|
||||||
|
windowClass.DockNodeFlagsOverrideSet = config.getDockNodeFlags();
|
||||||
|
ImGui::SetNextWindowClass(&windowClass);
|
||||||
|
|
||||||
|
const ImGuiCond cond = config.getPlacementCond();
|
||||||
|
if (config.size.x > 0.0f || config.size.y > 0.0f) {
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(config.size.x, config.size.y), cond);
|
||||||
|
}
|
||||||
|
if (config.position) {
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(config.position->x, config.position->y),
|
||||||
|
cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool open = true;
|
||||||
|
ImGui::Begin(config.name.c_str(), config.hasCloseButton() ? &open : nullptr,
|
||||||
|
config.getWindowFlags());
|
||||||
|
onUpdate(frameInfo);
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sophia
|
||||||
@@ -80,7 +80,7 @@ u32 PanelRegistry::visibleCount() const {
|
|||||||
void PanelRegistry::update(const FrameInfo& frameInfo) {
|
void PanelRegistry::update(const FrameInfo& frameInfo) {
|
||||||
for (auto& slot : slots) {
|
for (auto& slot : slots) {
|
||||||
if (slot.panel && slot.panel->isVisible()) {
|
if (slot.panel && slot.panel->isVisible()) {
|
||||||
slot.panel->onUpdate(frameInfo);
|
slot.panel->draw(frameInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,8 +111,6 @@ int ConsolePanel::textEditCallback(ImGuiInputTextCallbackData* data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ConsolePanel::onUpdate(const FrameInfo&) {
|
void ConsolePanel::onUpdate(const FrameInfo&) {
|
||||||
ImGui::Begin("Console");
|
|
||||||
|
|
||||||
if (ImGui::SmallButton("Clear")) {
|
if (ImGui::SmallButton("Clear")) {
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
@@ -161,8 +159,6 @@ void ConsolePanel::onUpdate(const FrameInfo&) {
|
|||||||
if (reclaimFocus) {
|
if (reclaimFocus) {
|
||||||
ImGui::SetKeyboardFocusHere(-1);
|
ImGui::SetKeyboardFocusHere(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ namespace sophia {
|
|||||||
class ConsolePanel : public Panel {
|
class ConsolePanel : public Panel {
|
||||||
public:
|
public:
|
||||||
explicit ConsolePanel(ConsoleCommandRegistry& consoleCommandRegistry)
|
explicit ConsolePanel(ConsoleCommandRegistry& consoleCommandRegistry)
|
||||||
: Panel{"Console"}, consoleCommandRegistry{consoleCommandRegistry} {
|
: Panel{{.name = "Console"}},
|
||||||
|
consoleCommandRegistry{consoleCommandRegistry} {
|
||||||
log("Console ready. Type 'help' for a list of commands.");
|
log("Console ready. Type 'help' for a list of commands.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
void EcsInspectorPanel::onUpdate(const FrameInfo&) {
|
void EcsInspectorPanel::onUpdate(const FrameInfo&) {
|
||||||
ImGui::Begin("ECS Inspector");
|
|
||||||
|
|
||||||
entityScratch.clear();
|
entityScratch.clear();
|
||||||
for (entt::entity entity : registry.storage<entt::entity>()) {
|
for (entt::entity entity : registry.storage<entt::entity>()) {
|
||||||
entityScratch.push_back(entity);
|
entityScratch.push_back(entity);
|
||||||
@@ -50,8 +48,6 @@ void EcsInspectorPanel::onUpdate(const FrameInfo&) {
|
|||||||
} else {
|
} else {
|
||||||
ImGui::TextDisabled("No entity selected");
|
ImGui::TextDisabled("No entity selected");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace sophia {
|
|||||||
class EcsInspectorPanel : public Panel {
|
class EcsInspectorPanel : public Panel {
|
||||||
public:
|
public:
|
||||||
explicit EcsInspectorPanel(entt::registry& registry)
|
explicit EcsInspectorPanel(entt::registry& registry)
|
||||||
: Panel{"ECS Inspector"}, registry{registry} {}
|
: Panel{{.name = "ECS Inspector"}}, registry{registry} {}
|
||||||
|
|
||||||
void onUpdate(const FrameInfo& frameInfo) override;
|
void onUpdate(const FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace sophia {
|
|||||||
|
|
||||||
class FrameStatsPanel : public Panel {
|
class FrameStatsPanel : public Panel {
|
||||||
public:
|
public:
|
||||||
FrameStatsPanel() : Panel{"Frame Stats"} {}
|
FrameStatsPanel() : Panel{{.name = "Frame Stats"}} {}
|
||||||
|
|
||||||
void onUpdate(const FrameInfo& frameInfo) override {
|
void onUpdate(const FrameInfo& frameInfo) override {
|
||||||
frameCount++;
|
frameCount++;
|
||||||
@@ -25,10 +25,8 @@ class FrameStatsPanel : public Panel {
|
|||||||
nextRefreshTime = frameInfo.elapsedTime + REFRESH_INTERVAL;
|
nextRefreshTime = frameInfo.elapsedTime + REFRESH_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Begin("Frame Stats");
|
|
||||||
ImGui::Text("FPS: %.1f", displayedFps);
|
ImGui::Text("FPS: %.1f", displayedFps);
|
||||||
ImGui::Text("Frame time: %.3f ms", displayedFrameTimeMs);
|
ImGui::Text("Frame time: %.3f ms", displayedFrameTimeMs);
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
void PanelRegistryPanel::onUpdate(const FrameInfo&) {
|
void PanelRegistryPanel::onUpdate(const FrameInfo&) {
|
||||||
ImGui::Begin("PanelRegistry");
|
|
||||||
ImGui::Text("%u panels (%u visible)", registry.size(),
|
ImGui::Text("%u panels (%u visible)", registry.size(),
|
||||||
registry.visibleCount());
|
registry.visibleCount());
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
@@ -21,8 +20,6 @@ void PanelRegistryPanel::onUpdate(const FrameInfo&) {
|
|||||||
panel->setVisible(visible);
|
panel->setVisible(visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sophia
|
} // namespace sophia
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace sophia {
|
|||||||
class PanelRegistryPanel : public Panel {
|
class PanelRegistryPanel : public Panel {
|
||||||
public:
|
public:
|
||||||
explicit PanelRegistryPanel(PanelRegistry& registry)
|
explicit PanelRegistryPanel(PanelRegistry& registry)
|
||||||
: Panel{"PanelRegistry"}, registry{registry} {}
|
: Panel{{.name = "PanelRegistry"}}, registry{registry} {}
|
||||||
|
|
||||||
void onUpdate(const FrameInfo& frameInfo) override;
|
void onUpdate(const FrameInfo& frameInfo) override;
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
#define GLFW_INCLUDE_VULKAN
|
#define GLFW_INCLUDE_VULKAN
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vulkan/vulkan.hpp>
|
|
||||||
|
|
||||||
#include <sophia/event.hpp>
|
#include <sophia/event.hpp>
|
||||||
#include <sophia/types.hpp>
|
#include <sophia/types.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
namespace sophia {
|
namespace sophia {
|
||||||
|
|
||||||
@@ -35,11 +34,8 @@ class Window {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static void resizeCallback(GLFWwindow* window, int width, int height);
|
static void resizeCallback(GLFWwindow* window, int width, int height);
|
||||||
static void keyEventCallback(GLFWwindow* window,
|
static void keyEventCallback(GLFWwindow* window, int key, int scancode,
|
||||||
int key,
|
int action, int mods);
|
||||||
int scancode,
|
|
||||||
int action,
|
|
||||||
int mods);
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|||||||
Reference in New Issue
Block a user