//- sixten: Rows and columns.
inline void UI_RowBegin(u32 Flags, string Name)
{
    UI_SetNextLayoutAxis(Axis2_X);
    ui_box *Box = UI_MakeBox(Flags, Name);
    UI_PushParent(Box);
}

inline void UI_RowEnd(void)
{
    UI_PopParent();
}

inline void UI_ColumnBegin(u32 Flags, string Name)
{
    UI_SetNextLayoutAxis(Axis2_Y);
    ui_box *Box = UI_MakeBox(Flags, Name);
    UI_PushParent(Box);
}

inline void UI_ColumnEnd(void)
{
    UI_PopParent();
}

//- sixten: Compositions
inline void UI_PushAxisSize(axis2 Axis, ui_size Size)
{
    if(Axis == Axis2_X)
    {
        UI_PushWidth(Size);
    }
    else
    {
        UI_PushHeight(Size);
    }
}

inline void UI_PopAxisSize(axis2 Axis)
{
    if(Axis == Axis2_X)
    {
        UI_PopWidth();
    }
    else
    {
        UI_PopHeight();
    }
}

inline void UI_SetNextAxisSize(axis2 Axis, ui_size Size)
{
    if(Axis == Axis2_X)
    {
        UI_SetNextWidth(Size);
    }
    else
    {
        UI_SetNextHeight(Size);
    }
}

//- sixten: Spacing
static ui_box *UI_NamedSpacer(ui_size Size, string String)
{
    ui_box *Parent = UI_TopParent();
    UI_SetNextAxisSize(Parent->LayoutAxis, Size);
    
    ui_box *Box = UI_MakeBox(0, String);
    return(Box);
}

static ui_box *UI_NamedSpacerF(ui_size Size, char *Format, ...)
{
    temporary_memory Scratch = GetScratch(0, 0);
    
    va_list Arguments;
    va_start(Arguments, Format);
    string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
    va_end(Arguments);
    
    ui_box *Box = UI_NamedSpacer(Size, String);
    
    ReleaseScratch(Scratch);
    
    return(Box);
}

static ui_box *UI_Spacer(ui_size Size)
{
    return(UI_NamedSpacer(Size, StrLit("")));
}

//- sixten: Scrollable regions


//- sixten: Common widgets
static ui_box *UI_Label(string String)
{
    ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
    return(Box);
}

static ui_box *UI_LabelF(char *Format, ...)
{
    temporary_memory Scratch = GetScratch(0, 0);
    
    va_list Arguments;
    va_start(Arguments, Format);
    string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
    va_end(Arguments);
    
    ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText, String);
    
    ReleaseScratch(Scratch);
    
    return(Box);
}

static ui_signal UI_Button(string String)
{
    UI_SetNextHoverCursor(PlatformCursor_Hand);
    ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
                             UI_BoxFlag_DrawBackground|
                             UI_BoxFlag_DrawBorder|
                             UI_BoxFlag_HotAnimation|
                             UI_BoxFlag_ActiveAnimation|
                             UI_BoxFlag_Clickable,
                             String);
    ui_signal Signal = UI_SignalFromBox(Box);
    return(Signal);
}

static ui_signal UI_ButtonF(char *Format, ...)
{
    temporary_memory Scratch = GetScratch(0, 0);
    
    UI_SetNextHoverCursor(PlatformCursor_Hand);
    
    va_list Arguments;
    va_start(Arguments, Format);
    string String = PushFormatVariadic(Scratch.Arena, Format, Arguments);
    va_end(Arguments);
    
    ui_box *Box = UI_MakeBox(UI_BoxFlag_DrawText|
                             UI_BoxFlag_DrawBackground|
                             UI_BoxFlag_DrawBorder|
                             UI_BoxFlag_HotAnimation|
                             UI_BoxFlag_ActiveAnimation|
                             UI_BoxFlag_Clickable,
                             String);
    ui_signal Signal = UI_SignalFromBox(Box);
    
    ReleaseScratch(Scratch);
    
    return(Signal);
}

static ui_signal UI_Checkbox(b32 *Checked, string String)
{
    UI_SetNextSize(UI_ChildrenSum(1, 1), UI_ChildrenSum(1, 1));
    UI_SetNextLayoutAxis(Axis2_X);
    UI_SetNextHoverCursor(PlatformCursor_Hand);
    ui_box *ContainerBox = UI_MakeBox(UI_BoxFlag_Clickable, String);
    UI_Parent(ContainerBox)
    {
        r32 OpacityTransition = AC_AnimateValueF(*Checked, *Checked, 0.15, "UI Checkbox Transition %p", Checked);
        
        v4 TextColor = UI_TopTextColor();
        TextColor.a = OpacityTransition;
        
        UI_CornerRadius(2) UI_Size(UI_Em(1, 1), UI_Em(1, 1)) UI_Font(Font_Icons) UI_TextColor(TextColor)
            UI_MakeBoxF(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawText, "%U", FontIcon_Cancel);
        
        UI_Size(UI_TextContent(15, 1), UI_Em(1, 1)) UI_Label(String);
    }
    
    ui_signal Signal = UI_SignalFromBox(ContainerBox);
    
    if(Signal.Pressed)
    {
        *Checked = !*Checked;
    }
    
    return(Signal);
}

//- sixten: Scrollable regions
static ui_signal UI_Scrollbar(axis2 Axis, string Name, r32 Size, r32 Offset)
{
    ui_signal Signal;
    
    UI_SetNextAxisSize(Axis, UI_Percent(1, 0));
    UI_SetNextAxisSize(Opposite(Axis), UI_Em(1, 1));
    UI_SetNextBackgroundColor(Darken(UI_TopBackgroundColor(), 2));
    UI_SetNextLayoutAxis(Axis);
    UI_Parent(UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, Name))
    {
        UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
        UI_SetNextFont(Font_Icons);
        UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_UpDir:FontIcon_LeftDir);
        
        UI_Spacer(UI_Pixels(Offset, 1));
        
        UI_SetNextCornerRadius(4.0f);
        UI_SetNextAxisSize(Axis, UI_Pixels(Size, 1));
        UI_SetNextAxisSize(Opposite(Axis), UI_Percent(1, 1));
        
        Signal = UI_SignalFromBox(UI_MakeBox(UI_BoxFlag_DrawBorder     |
                                             UI_BoxFlag_DrawBackground |
                                             UI_BoxFlag_Clickable      |
                                             UI_BoxFlag_HotAnimation   |
                                             UI_BoxFlag_ActiveAnimation,
                                             StrLit("Slider")));
        
        UI_Spacer(UI_Percent(1, 0));
        
        UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
        UI_SetNextFont(Font_Icons);
        UI_MakeBoxF(UI_BoxFlag_DrawText, "%U", Axis?FontIcon_DownDir:FontIcon_RightDir);
    }
    
    return(Signal);
}

static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
{
    b32 AllowOnX = (X != 0);
    b32 AllowOnY = (Y != 0);
    
    UI_RowBegin(Flags, Name);
    {
        UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
        UI_ColumnBegin();
        {
            u32 ScrollFlags = 0;
            if(AllowOnX)
            {
                ScrollFlags |= UI_BoxFlag_OverflowX;
                UI_SetNextOffsetX(-(*X));
            }
            
            if(AllowOnY)
            {
                ScrollFlags |= UI_BoxFlag_OverflowY;
                UI_SetNextOffsetY(-(*Y));
            }
            
            UI_SetNextSize(AllowOnX?UI_ChildrenSum(1, 1):UI_Percent(1, 0),
                           AllowOnY?UI_ChildrenSum(1, 1):UI_Percent(1, 0));
            
            ui_box *ScrollableBox = UI_MakeBox(ScrollFlags, StrLit("Scrollable Box"));
            
            UI_PushParent(ScrollableBox);
        }
    }
}

static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
{
    b32 AllowOnX = (X != 0);
    b32 AllowOnY = (Y != 0);
    
    ui_box *ScrollableBox = UI_TopParent();
    ui_signal ScrollableBoxSignal = UI_SignalFromBox(ScrollableBox);
    {
        {
            UI_PopParent();
            
            if(AllowOnX)
            {
                r32 TotalWidth = UI_CalculateBoxSize(ScrollableBox, Axis2_X);
                r32 ViewWidth = UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_X);
                
                if(ViewWidth / TotalWidth < 1)
                {
                    r32 TotalScrollWidth = ViewWidth - ScrollableBox->FontSize*2;
                    r32 ScrollScale = TotalScrollWidth / TotalWidth;
                    
                    // sixten(TODO): Add a max of 1 em, and figure out the associated algebra.
                    r32 ScrollWidth = ViewWidth*ScrollScale;
                    r32 ScrollOffset = (*X)*ScrollScale;
                    
                    ui_signal Signal = UI_Scrollbar(Axis2_X, StrLit("Scroll X"), ScrollWidth, ScrollOffset);
                    {
                        if(Signal.Dragging)
                        {
                            if(Signal.Pressed)
                            {
                                UI_StoreDragR32(*X);
                            }
                            
                            r32 StartOffset = UI_GetDragR32();
                            r32 EndOffset = StartOffset + Signal.DragDelta.x/ScrollScale;
                            
                            AC_AnimateValueDirect(EndOffset, 0.2, X);
                        }
                    }
                }
                *X = Clamp(*X, 0, Max(0.0, TotalWidth - ViewWidth));
            }
        }
        UI_ColumnEnd();
        
        if(AllowOnY)
        {
            UI_SetNextSize(UI_ChildrenSum(1, 1), UI_Percent(1, 0));
            UI_Column()
            {
                r32 TotalHeight = UI_CalculateBoxSize(ScrollableBox, Axis2_Y);
                r32 ViewHeight = DimOfRange(ScrollableBox->Parent->Parent->Rect).y;//UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_Y);
                
                if(ViewHeight / TotalHeight < 1)
                {
                    r32 TotalScrollHeight = ViewHeight - ScrollableBox->FontSize*2;
                    r32 ScrollScale = TotalScrollHeight / TotalHeight;
                    
                    // sixten(TODO): Add a max of 1 em, and figure out the associated algebra.
                    r32 ScrollHeight = ViewHeight*ScrollScale;
                    r32 ScrollOffset = (*Y)*ScrollScale;
                    
                    ui_signal Signal = UI_Scrollbar(Axis2_Y, StrLit("Scroll Y"), ScrollHeight, ScrollOffset);
                    {
                        if(Signal.Dragging)
                        {
                            if(Signal.Pressed)
                            {
                                UI_StoreDragR32(*Y);
                            }
                            
                            r32 StartOffset = UI_GetDragR32();
                            r32 EndOffset = StartOffset + Signal.DragDelta.y/ScrollScale;
                            
                            AC_AnimateValueDirect(EndOffset, 0.2, Y);
                        }
                    }
                }
                *Y = Clamp(*Y, 0, Max(0.0, TotalHeight - ViewHeight));
            }
            // sixten: Add padding
            if(AllowOnX && AllowOnY)
            {
                UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
                UI_SetNextBackgroundColor(Darken(UI_TopBackgroundColor(), 2));
                UI_MakeBox(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, StrLit("Padding"));
            }
        }
    }
    UI_RowEnd();
}

static r32 UI_Slider(r32 Value, range1_r32 Range)
{
    r32 Result = Value;
    UI_Column()
    {
        UI_Spacer(UI_Em(1, 1));
        UI_Height(UI_Em(1, 1)) UI_Row()
        {
            UI_SetNextWidth(UI_Em(20, 1));
            UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
            ui_box *Container = UI_MakeBoxF(UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, "Scrollable");
            UI_Parent(Container)
            {
                UI_SetNextCornerRadius(UI_TopFontSize()*0.5f);
                UI_SetNextSize(UI_Em(1, 1), UI_Em(1, 1));
                UI_SetNextFixedX((DimOfRange(Container->Rect).x-UI_TopFontSize())*(Value-Range.Min)/DimOfRange(Range));
                ui_box *Box = UI_MakeBoxF(UI_BoxFlag_DrawBackground|
                                          UI_BoxFlag_DrawBorder|
                                          UI_BoxFlag_HotAnimation|
                                          UI_BoxFlag_ActiveAnimation|
                                          UI_BoxFlag_Clickable|
                                          UI_BoxFlag_FloatingX|
                                          0, "Dragable");
                ui_signal Signal = UI_SignalFromBox(Box);
                if(Signal.Dragging)
                {
                    if(Signal.Pressed)
                    {
                        UI_StoreDragR32(Value);
                    }
                    
                    r32 StartT = UI_GetDragR32();
                    r32 EndT = StartT + Signal.DragDelta.x/(DimOfRange(Container->Rect).x-UI_TopFontSize());
                    Result = EndT*DimOfRange(Range)+Range.Min;
                }
            }
        }
    }
    return(Result);
}

static void UI_TooltipLabel(string Label, v2 P)
{
    UI_Tooltip
    {
        UI_SetNextSize(UI_TextContent(7, 1), UI_TextContent(3, 1));
        UI_CornerRadius(4);
        UI_SetNextFixedP(P+V2R32(15.0f, 0.0f));
        UI_MakeBox(UI_BoxFlag_DrawBorder     |
                   UI_BoxFlag_DrawBackground |
                   UI_BoxFlag_DrawText       |
                   UI_BoxFlag_DrawDropShadow |
                   UI_BoxFlag_FloatingX      |
                   UI_BoxFlag_FloatingY,
                   Label);
    }
}