194 lines
7.0 KiB
C++
194 lines
7.0 KiB
C++
|
|
#include "BorderlessWindowChrome.h"
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <cmath>
|
||
|
|
|
||
|
|
namespace XCEngine::UI::Editor::Host {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
using ::XCEngine::UI::UIColor;
|
||
|
|
using ::XCEngine::UI::UIDrawList;
|
||
|
|
using ::XCEngine::UI::UIPoint;
|
||
|
|
using ::XCEngine::UI::UIRect;
|
||
|
|
|
||
|
|
constexpr UIColor kTransparentColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||
|
|
|
||
|
|
float ResolveGlyphBoxSize(const UIRect& rect, float ratio, float minSize) {
|
||
|
|
return (std::max)(minSize, static_cast<float>(std::round(rect.height * ratio)));
|
||
|
|
}
|
||
|
|
|
||
|
|
void AppendMinimizeGlyph(
|
||
|
|
UIDrawList& drawList,
|
||
|
|
const UIRect& rect,
|
||
|
|
const UIColor& color,
|
||
|
|
float thickness) {
|
||
|
|
const float centerX = rect.x + rect.width * 0.5f;
|
||
|
|
const float centerY = rect.y + rect.height * 0.5f;
|
||
|
|
const float halfWidth = ResolveGlyphBoxSize(rect, 0.38f, 10.0f) * 0.5f;
|
||
|
|
const float y = centerY;
|
||
|
|
drawList.AddLine(
|
||
|
|
UIPoint(centerX - halfWidth, y),
|
||
|
|
UIPoint(centerX + halfWidth, y),
|
||
|
|
color,
|
||
|
|
thickness);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AppendMaximizeGlyph(
|
||
|
|
UIDrawList& drawList,
|
||
|
|
const UIRect& rect,
|
||
|
|
const UIColor& color,
|
||
|
|
float thickness) {
|
||
|
|
const float centerX = rect.x + rect.width * 0.5f;
|
||
|
|
const float centerY = rect.y + rect.height * 0.5f;
|
||
|
|
const float boxSize = ResolveGlyphBoxSize(rect, 0.32f, 9.0f);
|
||
|
|
const float halfExtent = boxSize * 0.5f;
|
||
|
|
const float left = centerX - halfExtent;
|
||
|
|
const float top = centerY - halfExtent;
|
||
|
|
const float right = left + boxSize;
|
||
|
|
const float bottom = top + boxSize;
|
||
|
|
drawList.AddLine(UIPoint(left, top), UIPoint(right, top), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(left, top), UIPoint(left, bottom), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(right, top), UIPoint(right, bottom), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(left, bottom), UIPoint(right, bottom), color, thickness);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AppendRestoreGlyph(
|
||
|
|
UIDrawList& drawList,
|
||
|
|
const UIRect& rect,
|
||
|
|
const UIColor& color,
|
||
|
|
float thickness) {
|
||
|
|
const float centerX = rect.x + rect.width * 0.5f;
|
||
|
|
const float centerY = rect.y + rect.height * 0.5f;
|
||
|
|
const float boxSize = ResolveGlyphBoxSize(rect, 0.29f, 8.0f);
|
||
|
|
const float halfExtent = boxSize * 0.5f;
|
||
|
|
const float offset = 1.0f;
|
||
|
|
|
||
|
|
const float backLeft = centerX - halfExtent + offset;
|
||
|
|
const float backTop = centerY - halfExtent - offset;
|
||
|
|
const float backRight = backLeft + boxSize;
|
||
|
|
const float backBottom = backTop + boxSize;
|
||
|
|
|
||
|
|
const float frontLeft = centerX - halfExtent - offset;
|
||
|
|
const float frontTop = centerY - halfExtent + offset;
|
||
|
|
const float frontRight = frontLeft + boxSize;
|
||
|
|
const float frontBottom = frontTop + boxSize;
|
||
|
|
|
||
|
|
drawList.AddLine(UIPoint(backLeft, backTop), UIPoint(backRight, backTop), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(backLeft, backTop), UIPoint(backLeft, frontTop), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(backRight, backTop), UIPoint(backRight, backBottom), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(frontRight, backBottom), UIPoint(backRight, backBottom), color, thickness);
|
||
|
|
|
||
|
|
drawList.AddLine(UIPoint(frontLeft, frontTop), UIPoint(frontRight, frontTop), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(frontLeft, frontTop), UIPoint(frontLeft, frontBottom), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(frontRight, frontTop), UIPoint(frontRight, frontBottom), color, thickness);
|
||
|
|
drawList.AddLine(UIPoint(frontLeft, frontBottom), UIPoint(frontRight, frontBottom), color, thickness);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AppendCloseGlyph(
|
||
|
|
UIDrawList& drawList,
|
||
|
|
const UIRect& rect,
|
||
|
|
const UIColor& color,
|
||
|
|
float thickness) {
|
||
|
|
const float centerX = rect.x + rect.width * 0.5f;
|
||
|
|
const float centerY = rect.y + rect.height * 0.5f;
|
||
|
|
const float halfWidth = ResolveGlyphBoxSize(rect, 0.29f, 8.0f) * 0.5f;
|
||
|
|
const float halfHeight = halfWidth;
|
||
|
|
drawList.AddLine(
|
||
|
|
UIPoint(centerX - halfWidth, centerY - halfHeight),
|
||
|
|
UIPoint(centerX + halfWidth, centerY + halfHeight),
|
||
|
|
color,
|
||
|
|
thickness);
|
||
|
|
drawList.AddLine(
|
||
|
|
UIPoint(centerX + halfWidth, centerY - halfHeight),
|
||
|
|
UIPoint(centerX - halfWidth, centerY + halfHeight),
|
||
|
|
color,
|
||
|
|
thickness);
|
||
|
|
}
|
||
|
|
|
||
|
|
UIColor ResolveButtonFillColor(
|
||
|
|
BorderlessWindowChromeHitTarget target,
|
||
|
|
const BorderlessWindowChromeState& state,
|
||
|
|
const BorderlessWindowChromePalette& palette) {
|
||
|
|
const bool hovered = state.hoveredTarget == target;
|
||
|
|
const bool pressed = state.pressedTarget == target;
|
||
|
|
if (target == BorderlessWindowChromeHitTarget::CloseButton) {
|
||
|
|
if (pressed) {
|
||
|
|
return palette.closeButtonPressedColor;
|
||
|
|
}
|
||
|
|
if (hovered) {
|
||
|
|
return palette.closeButtonHoverColor;
|
||
|
|
}
|
||
|
|
return kTransparentColor;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (pressed) {
|
||
|
|
return palette.buttonPressedColor;
|
||
|
|
}
|
||
|
|
if (hovered) {
|
||
|
|
return palette.buttonHoverColor;
|
||
|
|
}
|
||
|
|
return kTransparentColor;
|
||
|
|
}
|
||
|
|
|
||
|
|
UIColor ResolveIconColor(
|
||
|
|
BorderlessWindowChromeHitTarget target,
|
||
|
|
const BorderlessWindowChromeState& state,
|
||
|
|
const BorderlessWindowChromePalette& palette) {
|
||
|
|
if (target == BorderlessWindowChromeHitTarget::CloseButton &&
|
||
|
|
(state.hoveredTarget == target || state.pressedTarget == target)) {
|
||
|
|
return palette.closeIconHoverColor;
|
||
|
|
}
|
||
|
|
|
||
|
|
return palette.iconColor;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
void AppendBorderlessWindowChrome(
|
||
|
|
UIDrawList& drawList,
|
||
|
|
const BorderlessWindowChromeLayout& layout,
|
||
|
|
const BorderlessWindowChromeState& state,
|
||
|
|
bool maximized,
|
||
|
|
const BorderlessWindowChromePalette& palette,
|
||
|
|
const BorderlessWindowChromeMetrics& metrics) {
|
||
|
|
const struct ButtonEntry {
|
||
|
|
BorderlessWindowChromeHitTarget target;
|
||
|
|
UIRect rect;
|
||
|
|
} buttons[] = {
|
||
|
|
{ BorderlessWindowChromeHitTarget::MinimizeButton, layout.minimizeButtonRect },
|
||
|
|
{ BorderlessWindowChromeHitTarget::MaximizeRestoreButton, layout.maximizeRestoreButtonRect },
|
||
|
|
{ BorderlessWindowChromeHitTarget::CloseButton, layout.closeButtonRect }
|
||
|
|
};
|
||
|
|
|
||
|
|
for (const ButtonEntry& button : buttons) {
|
||
|
|
const UIColor fill = ResolveButtonFillColor(button.target, state, palette);
|
||
|
|
if (fill.a > 0.0f) {
|
||
|
|
drawList.AddFilledRect(button.rect, fill);
|
||
|
|
}
|
||
|
|
|
||
|
|
const UIColor iconColor = ResolveIconColor(button.target, state, palette);
|
||
|
|
switch (button.target) {
|
||
|
|
case BorderlessWindowChromeHitTarget::MinimizeButton:
|
||
|
|
AppendMinimizeGlyph(drawList, button.rect, iconColor, metrics.iconThickness);
|
||
|
|
break;
|
||
|
|
case BorderlessWindowChromeHitTarget::MaximizeRestoreButton:
|
||
|
|
if (maximized) {
|
||
|
|
AppendRestoreGlyph(drawList, button.rect, iconColor, metrics.iconThickness);
|
||
|
|
} else {
|
||
|
|
AppendMaximizeGlyph(drawList, button.rect, iconColor, metrics.iconThickness);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case BorderlessWindowChromeHitTarget::CloseButton:
|
||
|
|
AppendCloseGlyph(drawList, button.rect, iconColor, metrics.iconThickness);
|
||
|
|
break;
|
||
|
|
case BorderlessWindowChromeHitTarget::DragRegion:
|
||
|
|
case BorderlessWindowChromeHitTarget::None:
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace XCEngine::UI::Editor::Host
|