Files
whetstone_DSL/editor/src/WindowHierarchyModel.h

143 lines
4.5 KiB
C++

#pragma once
// Step 512: Window Chrome + Hierarchy Pass
// Headless hierarchy model for surface classification and deterministic
// elevation/layering semantics between work surfaces, tool surfaces, and overlays.
#include <string>
#include <vector>
#include <algorithm>
struct SurfaceStyle {
float borderAlpha = 0.0f;
float shadowAlpha = 0.0f;
float edgeHighlightAlpha = 0.0f;
int zIndex = 0;
};
enum class SurfaceRole {
Work,
Tool,
Overlay,
Modal,
Notification
};
struct SurfaceNode {
std::string id;
SurfaceRole role = SurfaceRole::Work;
bool modal = false;
bool interactive = true;
int depth = 0;
SurfaceStyle style;
};
struct HierarchyReport {
bool valid = true;
std::vector<SurfaceNode> ordered;
std::vector<std::string> violations;
};
class WindowHierarchyModel {
public:
static SurfaceStyle styleForRole(SurfaceRole role, int depth) {
SurfaceStyle s;
switch (role) {
case SurfaceRole::Work:
s.borderAlpha = 0.28f;
s.shadowAlpha = 0.05f;
s.edgeHighlightAlpha = 0.10f;
s.zIndex = 100 + depth;
break;
case SurfaceRole::Tool:
s.borderAlpha = 0.34f;
s.shadowAlpha = 0.10f;
s.edgeHighlightAlpha = 0.16f;
s.zIndex = 200 + depth;
break;
case SurfaceRole::Overlay:
s.borderAlpha = 0.40f;
s.shadowAlpha = 0.20f;
s.edgeHighlightAlpha = 0.24f;
s.zIndex = 300 + depth;
break;
case SurfaceRole::Modal:
s.borderAlpha = 0.46f;
s.shadowAlpha = 0.28f;
s.edgeHighlightAlpha = 0.30f;
s.zIndex = 400 + depth;
break;
case SurfaceRole::Notification:
s.borderAlpha = 0.42f;
s.shadowAlpha = 0.18f;
s.edgeHighlightAlpha = 0.26f;
s.zIndex = 350 + depth;
break;
}
return s;
}
static HierarchyReport validateAndOrder(const std::vector<SurfaceNode>& input) {
HierarchyReport out;
out.ordered = input;
for (auto& n : out.ordered) {
n.style = styleForRole(n.role, n.depth);
}
std::sort(out.ordered.begin(), out.ordered.end(),
[](const SurfaceNode& a, const SurfaceNode& b) {
if (a.style.zIndex != b.style.zIndex) return a.style.zIndex < b.style.zIndex;
return a.id < b.id;
});
bool seenModal = false;
for (size_t i = 0; i < out.ordered.size(); ++i) {
const auto& n = out.ordered[i];
if (n.role == SurfaceRole::Modal) {
seenModal = true;
if (!n.modal) {
out.valid = false;
out.violations.push_back("modal-flag-missing:" + n.id);
}
}
if (seenModal && n.role == SurfaceRole::Work) {
out.valid = false;
out.violations.push_back("work-above-modal:" + n.id);
}
}
for (const auto& n : out.ordered) {
if (n.role == SurfaceRole::Overlay && n.style.zIndex < 300) {
out.valid = false;
out.violations.push_back("overlay-z-too-low:" + n.id);
}
if (n.role == SurfaceRole::Tool && n.style.zIndex < 200) {
out.valid = false;
out.violations.push_back("tool-z-too-low:" + n.id);
}
}
return out;
}
static std::vector<SurfaceNode> normalize(const std::vector<SurfaceNode>& input) {
std::vector<SurfaceNode> out = input;
for (auto& n : out) {
if (n.role == SurfaceRole::Modal) n.modal = true;
n.style = styleForRole(n.role, n.depth);
}
std::sort(out.begin(), out.end(),
[](const SurfaceNode& a, const SurfaceNode& b) {
return a.style.zIndex < b.style.zIndex;
});
return out;
}
static bool blocksInteraction(const SurfaceNode& top, const SurfaceNode& bottom) {
if (!top.interactive) return false;
if (top.role == SurfaceRole::Modal && top.style.zIndex > bottom.style.zIndex) return true;
if (top.role == SurfaceRole::Overlay && top.style.zIndex > bottom.style.zIndex) return true;
return false;
}
};