Supporting setting panel layout

This commit is contained in:
2026-09-19 19:41:39 -07:00
parent ace69f613e
commit da6bda7ca7
24 changed files with 257 additions and 37 deletions
+65 -2
View File
@@ -3,9 +3,21 @@
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_vulkan.h>
#include <imgui_internal.h> // DockBuilder API
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,
vk::Format colorAttachmentFormat,
u32 minImageCount) {
@@ -65,8 +77,59 @@ void ImGuiRenderer::beginFrame() {
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(),
ImGuiDockNodeFlags_PassthruCentralNode);
ImGuiID dockspaceId = ImGui::DockSpaceOverViewport(
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, &center);
// 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, &center);
const ImGuiID bottom = ImGui::DockBuilderSplitNode(
center, ImGuiDir_Down, defaultLayout.bottomHeight, nullptr, &center);
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) {