//- 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_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 = 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); } }