namespace AcDream.App.UI;
///
/// Retail UIElement_Resizebar (element class 9,
/// UIElement_Resizebar::Register @0x0046B920 registers class 9 with the
/// LayoutDesc element factory). A leaf grip authored at exactly one edge or
/// corner of a window; retail authors 4 edge grips + 4 corner grips per
/// resizable window (main chat: 0x1000069B-0x100006A2, minus the
/// straight top strip which is a retail UIElement_Dragbar move handle
/// instead — see the class doc on
/// and docs/research/2026-08-09-chat-retail-window-shell.md §2.1/§2.3).
///
///
/// UIElement_Resizebar::StartMouseResizing @0x0046B7E0 reads four BOOL
/// attributes off the element — 0x2A=bottom, 0x2B=left,
/// 0x2C=right, 0x2D=top — and combines them into a
/// BorderLocation (acclient.h:4327).
/// is a verbatim port of that branch order. acdream's engine expresses resize
/// direction as an edge-flag bitmask () rather than
/// retail's nine-case enum; is the lossless projection —
/// every value maps to exactly one
/// combination and back.
///
///
///
/// A grip is a small (5px) leaf with no children and no authored background
/// media beyond its own cursor-feedback sprite; it exists purely as a precise
/// hit region. gives a directly-hit grip's
/// own priority over the generic proximity-based
/// heuristic, so e.g. the chat
/// window's top-left/top-right CORNER grips resize (including the Y/top axis)
/// while the plain top EDGE strip in between remains a pure move handle.
///
///
public sealed class UiResizeGrip : UiElement
{
/// Retail BorderLocation (acclient.h:4327):
/// BORDER_NONE=0, BORDER_UL=1, BORDER_TOP=2, BORDER_UR=3, BORDER_RIGHT=4,
/// BORDER_LR=5, BORDER_BOTTOM=6, BORDER_LL=7, BORDER_LEFT=8.
public enum Border
{
None = 0,
UpperLeft = 1,
Top = 2,
UpperRight = 3,
Right = 4,
LowerRight = 5,
Bottom = 6,
LowerLeft = 7,
Left = 8,
}
/// Decoded retail BorderLocation for this grip.
public Border BorderLocation { get; set; }
///
/// Exact port of UIElement_Resizebar::StartMouseResizing @0x0046B7E0's
/// if/else-if chain (right beats left beats top beats bottom when more than
/// two bools are set, which retail's authored data never does — corners set
/// exactly two adjacent bools, edges set exactly one).
///
public static Border DecodeBorderLocation(bool bottom, bool left, bool right, bool top)
{
if (right) return top ? Border.UpperRight : bottom ? Border.LowerRight : Border.Right;
if (left) return top ? Border.UpperLeft : bottom ? Border.LowerLeft : Border.Left;
if (top) return Border.Top;
if (bottom) return Border.Bottom;
return Border.None;
}
/// The projection 's resize
/// drag state machine consumes — a lossless re-encoding of .
public ResizeEdges Edges => BorderLocation switch
{
Border.UpperLeft => ResizeEdges.Left | ResizeEdges.Top,
Border.Top => ResizeEdges.Top,
Border.UpperRight => ResizeEdges.Right | ResizeEdges.Top,
Border.Right => ResizeEdges.Right,
Border.LowerRight => ResizeEdges.Right | ResizeEdges.Bottom,
Border.Bottom => ResizeEdges.Bottom,
Border.LowerLeft => ResizeEdges.Left | ResizeEdges.Bottom,
Border.Left => ResizeEdges.Left,
_ => ResizeEdges.None,
};
}