#include "BorderlessWindowChrome.h" #include #include 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(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