Three preset layouts (VSCode/Emacs/JetBrains) with panel visibility, size ratios, dirty flag for rebuild, and file-based persistence. Also includes revised sprint4_plan.md and new sprint5_plan.md. 10/10 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
191 lines
6.6 KiB
C++
191 lines
6.6 KiB
C++
// LayoutManager.h — Docking layout presets (Step 76)
|
||
//
|
||
// Defines preset layouts (VSCode, Emacs, JetBrains) with panel sizes
|
||
// and dock configuration. The actual ImGui DockBuilder calls happen in
|
||
// main.cpp; LayoutManager provides the declarative data.
|
||
//
|
||
// Presets:
|
||
// VSCode — Explorer 20% left, Editor 60% center, Panel 20% bottom
|
||
// Emacs — Full-frame editor, optional side panels, minibuffer bar
|
||
// JetBrains — Project tree 20% left, Editor center, tool windows right+bottom
|
||
|
||
#pragma once
|
||
#include <string>
|
||
#include <vector>
|
||
#include <map>
|
||
#include <fstream>
|
||
#include <algorithm>
|
||
|
||
// ---- Enums ----------------------------------------------------------------
|
||
|
||
enum class LayoutPreset { VSCode, Emacs, JetBrains };
|
||
|
||
enum class DockDirection { Left, Right, Bottom, Top, Center };
|
||
|
||
// ---- Data types -----------------------------------------------------------
|
||
|
||
struct DockPanel {
|
||
std::string id; // ImGui window name ("Explorer", "Editor", "Panel", etc.)
|
||
DockDirection direction; // Where this panel docks relative to the main area
|
||
float sizeRatio; // Fraction of the split axis (0.0 – 1.0)
|
||
bool visible; // Starts visible?
|
||
};
|
||
|
||
struct LayoutConfig {
|
||
LayoutPreset preset;
|
||
std::string name;
|
||
std::string description;
|
||
std::vector<DockPanel> panels;
|
||
bool showStatusBar = true;
|
||
};
|
||
|
||
// ---- LayoutManager --------------------------------------------------------
|
||
|
||
class LayoutManager {
|
||
LayoutPreset currentPreset_ = LayoutPreset::VSCode;
|
||
std::map<LayoutPreset, LayoutConfig> presets_;
|
||
bool layoutDirty_ = true;
|
||
|
||
public:
|
||
LayoutManager() { initPresets(); }
|
||
|
||
// --- Preset access ------------------------------------------------------
|
||
|
||
static std::vector<LayoutPreset> availablePresets() {
|
||
return { LayoutPreset::VSCode, LayoutPreset::Emacs, LayoutPreset::JetBrains };
|
||
}
|
||
|
||
static const char* presetName(LayoutPreset p) {
|
||
switch (p) {
|
||
case LayoutPreset::VSCode: return "VSCode";
|
||
case LayoutPreset::Emacs: return "Emacs";
|
||
case LayoutPreset::JetBrains: return "JetBrains";
|
||
}
|
||
return "Unknown";
|
||
}
|
||
|
||
static LayoutPreset presetFromName(const std::string& name) {
|
||
if (name == "Emacs") return LayoutPreset::Emacs;
|
||
if (name == "JetBrains") return LayoutPreset::JetBrains;
|
||
return LayoutPreset::VSCode; // default
|
||
}
|
||
|
||
// --- Current preset -----------------------------------------------------
|
||
|
||
LayoutPreset getPreset() const { return currentPreset_; }
|
||
|
||
void setPreset(LayoutPreset p) {
|
||
if (currentPreset_ != p) {
|
||
currentPreset_ = p;
|
||
layoutDirty_ = true;
|
||
}
|
||
}
|
||
|
||
bool isLayoutDirty() const { return layoutDirty_; }
|
||
void clearDirty() { layoutDirty_ = false; }
|
||
void markDirty() { layoutDirty_ = true; }
|
||
|
||
const LayoutConfig& getConfig() const {
|
||
return presets_.at(currentPreset_);
|
||
}
|
||
|
||
const LayoutConfig& getConfig(LayoutPreset p) const {
|
||
return presets_.at(p);
|
||
}
|
||
|
||
// --- Panel queries ------------------------------------------------------
|
||
|
||
const DockPanel* findPanel(const std::string& panelId) const {
|
||
const auto& cfg = getConfig();
|
||
for (const auto& p : cfg.panels) {
|
||
if (p.id == panelId) return &p;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
bool isPanelVisible(const std::string& panelId) const {
|
||
const auto* p = findPanel(panelId);
|
||
return p ? p->visible : false;
|
||
}
|
||
|
||
std::vector<std::string> getVisiblePanelIds() const {
|
||
std::vector<std::string> ids;
|
||
const auto& cfg = getConfig();
|
||
for (const auto& p : cfg.panels) {
|
||
if (p.visible) ids.push_back(p.id);
|
||
}
|
||
return ids;
|
||
}
|
||
|
||
float getPanelRatio(const std::string& panelId) const {
|
||
const auto* p = findPanel(panelId);
|
||
return p ? p->sizeRatio : 0.0f;
|
||
}
|
||
|
||
// --- Persistence (simple key=value) -------------------------------------
|
||
|
||
bool saveToFile(const std::string& path) const {
|
||
std::ofstream f(path);
|
||
if (!f.is_open()) return false;
|
||
f << "layout=" << presetName(currentPreset_) << "\n";
|
||
return true;
|
||
}
|
||
|
||
bool loadFromFile(const std::string& path) {
|
||
std::ifstream f(path);
|
||
if (!f.is_open()) return false;
|
||
std::string line;
|
||
while (std::getline(f, line)) {
|
||
if (line.substr(0, 7) == "layout=") {
|
||
setPreset(presetFromName(line.substr(7)));
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private:
|
||
void initPresets() {
|
||
// ---- VSCode --------------------------------------------------------
|
||
LayoutConfig vscode;
|
||
vscode.preset = LayoutPreset::VSCode;
|
||
vscode.name = "VSCode";
|
||
vscode.description = "Explorer 20% left, Editor center, Panel 20% bottom, status bar";
|
||
vscode.showStatusBar = true;
|
||
vscode.panels = {
|
||
{ "Explorer", DockDirection::Left, 0.20f, true },
|
||
{ "Editor", DockDirection::Center, 0.60f, true },
|
||
{ "Panel", DockDirection::Bottom, 0.20f, true },
|
||
};
|
||
presets_[LayoutPreset::VSCode] = std::move(vscode);
|
||
|
||
// ---- Emacs ---------------------------------------------------------
|
||
LayoutConfig emacs;
|
||
emacs.preset = LayoutPreset::Emacs;
|
||
emacs.name = "Emacs";
|
||
emacs.description = "Full-frame editor, optional side panels, minibuffer bottom bar";
|
||
emacs.showStatusBar = true;
|
||
emacs.panels = {
|
||
{ "Explorer", DockDirection::Left, 0.15f, false },
|
||
{ "Editor", DockDirection::Center, 0.85f, true },
|
||
{ "Minibuffer", DockDirection::Bottom, 0.04f, true },
|
||
{ "Panel", DockDirection::Bottom, 0.15f, false },
|
||
};
|
||
presets_[LayoutPreset::Emacs] = std::move(emacs);
|
||
|
||
// ---- JetBrains -----------------------------------------------------
|
||
LayoutConfig jb;
|
||
jb.preset = LayoutPreset::JetBrains;
|
||
jb.name = "JetBrains";
|
||
jb.description = "Project tree left, Editor center, tool windows right and bottom";
|
||
jb.showStatusBar = true;
|
||
jb.panels = {
|
||
{ "Explorer", DockDirection::Left, 0.20f, true },
|
||
{ "Editor", DockDirection::Center, 0.50f, true },
|
||
{ "ToolWindow", DockDirection::Right, 0.15f, true },
|
||
{ "Panel", DockDirection::Bottom, 0.25f, true },
|
||
};
|
||
presets_[LayoutPreset::JetBrains] = std::move(jb);
|
||
}
|
||
};
|