Lay out the overlay panels in a fixed 3-column scheme

Panels used to Begin at cascade positions, so they overlapped and clipped. A new
apply_panel_layout() in app_chrome positions/sizes each panel from the main
viewport work area (ImGuiCond_FirstUseEver, still movable): Injection left column
full height (room for hook diagnostics), Controllers/Video/Audio stacked in the
center column, Log right edge full height (max room for the log stream). Added a
"View -> Reset layout" menu item (request_layout_reset / apply_layout_end_frame
re-apply the defaults once via ImGuiCond_Always). Each panel now calls
apply_panel_layout(Panel::X) instead of its own ad-hoc SetNextWindowPos/Size.

Verified live: captured the host overlay -- Injection (left, full height),
Controllers/Video/Audio (center stack), Log (right, full height), no overlap among
the panels. x64 build + ctest green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 01:19:45 +02:00
parent 80cc5e72bd
commit 37d0f64e23
9 changed files with 105 additions and 21 deletions

View File

@@ -1,5 +1,6 @@
#include "ui/app_chrome.hpp"
#include <algorithm>
#include <cstdio>
#include "imgui.h"
@@ -7,6 +8,72 @@
namespace coop
{
namespace
{
// Set by "View -> Reset layout"; true for the one frame in which panels re-apply
// their default position/size, then cleared by apply_layout_end_frame().
bool g_layout_reset = false;
} // namespace
void request_layout_reset()
{
g_layout_reset = true;
}
void apply_layout_end_frame()
{
g_layout_reset = false;
}
void apply_panel_layout(Panel panel)
{
const ImGuiViewport* vp = ImGui::GetMainViewport();
const ImVec2 o = vp->WorkPos; // below the main menu bar
const ImVec2 s = vp->WorkSize;
const float m = 12.0f; // outer margin
const float gap = 10.0f; // between panels
const float left_w = 440.0f; // Injection (window list + hook diagnostics)
const float right_w = 380.0f; // Log
const float center_x = o.x + m + left_w + gap;
const float right_x = o.x + s.x - right_w - m;
const float center_w = std::max(360.0f, right_x - gap - center_x);
const float full_h = std::max(200.0f, s.y - 2.0f * m);
const float ctrl_h = 210.0f; // Controllers
const float vid_h = 250.0f; // Video mirror
const float audio_y = o.y + m + ctrl_h + gap + vid_h + gap;
const float bottom = o.y + m + full_h;
ImVec2 pos, size;
switch (panel)
{
case Panel::Injection:
pos = ImVec2(o.x + m, o.y + m);
size = ImVec2(left_w, full_h);
break;
case Panel::Controllers:
pos = ImVec2(center_x, o.y + m);
size = ImVec2(center_w, ctrl_h);
break;
case Panel::Video:
pos = ImVec2(center_x, o.y + m + ctrl_h + gap);
size = ImVec2(center_w, vid_h);
break;
case Panel::Audio:
pos = ImVec2(center_x, audio_y);
size = ImVec2(center_w, std::max(180.0f, bottom - audio_y));
break;
case Panel::Log:
pos = ImVec2(right_x, o.y + m);
size = ImVec2(right_w, full_h);
break;
}
const ImGuiCond cond = g_layout_reset ? ImGuiCond_Always : ImGuiCond_FirstUseEver;
ImGui::SetNextWindowPos(pos, cond);
ImGui::SetNextWindowSize(size, cond);
}
float draw_main_menu_bar(UiState& ui, const FrameStats& stats)
{
float height = 0.0f;
@@ -27,6 +94,10 @@ float draw_main_menu_bar(UiState& ui, const FrameStats& stats)
ImGui::MenuItem("Log", nullptr, &ui.show_log);
ImGui::Separator();
ImGui::MenuItem("Debug details", nullptr, &ui.debug_details);
if (ImGui::MenuItem("Reset layout"))
{
request_layout_reset();
}
ImGui::EndMenu();
}

View File

@@ -22,6 +22,27 @@ struct UiState
bool debug_details = false; // off = general status; on = full diagnostics
};
// The overlay panels, for the shared default layout below.
enum class Panel
{
Injection, // left column, full height (room for hook diagnostics)
Controllers, // center column, top
Video, // center column, below Controllers
Audio, // center column, below Video
Log, // right column, full height (max room for the log stream)
};
// Position + size the next ImGui window per the default 3-column layout, so panels
// open without overlapping or needing a manual resize. First-use only, unless a
// layout reset was just requested (then it re-applies once). Call right before the
// panel's ImGui::Begin.
void apply_panel_layout(Panel panel);
// "View -> Reset layout" sets this; it forces apply_panel_layout to re-place every
// panel on the next frame. apply_layout_end_frame() clears it after the panels draw.
void request_layout_reset();
void apply_layout_end_frame();
// Rolling frame-timing over a ~1 s window, recomputed each window so the status
// bar can show a stable FPS plus the min/max frame time (jitter) underneath it.
class FrameStats