vn/code/vn_ui_utils.cpp

436 lines
14 KiB
C++
Raw Normal View History

2023-06-27 14:14:28 +00:00
//- sixten: Rows and columns.
inline void UI_RowBegin(u32 Flags, string Name)
2023-06-17 17:00:55 +00:00
{
UI_SetNextLayoutAxis(Axis2_X);
2023-06-27 14:14:28 +00:00
ui_box *Box = UI_MakeBox(Flags, Name);
2023-06-17 17:00:55 +00:00
UI_PushParent(Box);
}
inline void UI_RowEnd(void)
{
UI_PopParent();
}
2023-06-27 14:14:28 +00:00
inline void UI_ColumnBegin(u32 Flags, string Name)
2023-06-17 17:00:55 +00:00
{
UI_SetNextLayoutAxis(Axis2_Y);
2023-06-27 14:14:28 +00:00
ui_box *Box = UI_MakeBox(Flags, Name);
2023-06-17 17:00:55 +00:00
UI_PushParent(Box);
}
inline void UI_ColumnEnd(void)
{
UI_PopParent();
}
2023-06-27 14:14:28 +00:00
//- sixten: Compositions
2023-06-17 17:00:55 +00:00
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);
}
}
2023-06-27 14:14:28 +00:00
//- sixten: Spacing
2023-06-17 17:00:55 +00:00
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);
}
2023-08-22 03:19:51 +00:00
static ui_box *UI_Spacer(ui_size Size)
2023-06-17 17:00:55 +00:00
{
2023-08-22 03:19:51 +00:00
return(UI_NamedSpacer(Size, StrLit("")));
2023-06-17 17:00:55 +00:00
}
2023-06-27 14:14:28 +00:00
//- sixten: Scrollable regions
2023-06-17 17:00:55 +00:00
2023-06-27 14:14:28 +00:00
//- sixten: Common widgets
2023-06-17 17:00:55 +00:00
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)
{
2023-08-22 03:19:51 +00:00
UI_SetNextHoverCursor(PlatformCursor_Hand);
2023-06-17 17:00:55 +00:00
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);
2023-08-22 03:19:51 +00:00
UI_SetNextHoverCursor(PlatformCursor_Hand);
2023-06-17 17:00:55 +00:00
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);
2023-06-19 17:12:26 +00:00
return(Signal);
}
2023-06-27 14:14:28 +00:00
static ui_signal UI_Checkbox(b32 *Checked, string String)
2023-06-19 17:12:26 +00:00
{
UI_SetNextSize(UI_ChildrenSum(1, 1), UI_ChildrenSum(1, 1));
UI_SetNextLayoutAxis(Axis2_X);
2023-08-22 03:19:51 +00:00
UI_SetNextHoverCursor(PlatformCursor_Hand);
2023-06-19 17:12:26 +00:00
ui_box *ContainerBox = UI_MakeBox(UI_BoxFlag_Clickable, String);
UI_Parent(ContainerBox)
{
2023-08-22 03:19:51 +00:00
r32 OpacityTransition = AC_AnimateValueF(*Checked, *Checked, 0.15, "UI Checkbox Transition %p", Checked);
2023-06-19 17:12:26 +00:00
v4 TextColor = UI_TopTextColor();
TextColor.a = OpacityTransition;
2023-06-23 12:38:15 +00:00
UI_CornerRadius(2) UI_Size(UI_Em(1, 1), UI_Em(1, 1)) UI_Font(Font_Icons) UI_TextColor(TextColor)
2023-06-19 17:12:26 +00:00
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);
2023-06-23 12:38:15 +00:00
2023-06-19 17:12:26 +00:00
if(Signal.Pressed)
{
*Checked = !*Checked;
}
2023-06-23 12:38:15 +00:00
2023-06-17 17:00:55 +00:00
return(Signal);
2023-06-27 14:14:28 +00:00
}
//- 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));
2023-09-05 17:50:49 +00:00
UI_SetNextCornerRadius(4.0f);
2023-06-27 14:14:28 +00:00
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);
}
2023-08-22 03:19:51 +00:00
static void UI_ScrollBegin(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
2023-06-27 14:14:28 +00:00
{
b32 AllowOnX = (X != 0);
b32 AllowOnY = (Y != 0);
2023-08-22 03:19:51 +00:00
UI_RowBegin(Flags, Name);
2023-06-27 14:14:28 +00:00
{
UI_SetNextSize(UI_Percent(1, 0), UI_Percent(1, 0));
UI_ColumnBegin();
{
2023-08-22 03:19:51 +00:00
u32 ScrollFlags = 0;
2023-06-27 14:14:28 +00:00
if(AllowOnX)
{
2023-08-22 03:19:51 +00:00
ScrollFlags |= UI_BoxFlag_OverflowX;
UI_SetNextOffsetX(-AC_AnimateValueF(*X, *X, 0.2f, "Scroll %S X", Name));
2023-06-27 14:14:28 +00:00
}
if(AllowOnY)
{
2023-08-22 03:19:51 +00:00
ScrollFlags |= UI_BoxFlag_OverflowY;
UI_SetNextOffsetY(-AC_AnimateValueF(*Y, *Y, 0.2f, "Scroll %S Y", Name));
2023-06-27 14:14:28 +00:00
}
UI_SetNextSize(AllowOnX?UI_ChildrenSum(1, 1):UI_Percent(1, 0),
AllowOnY?UI_ChildrenSum(1, 1):UI_Percent(1, 0));
2023-08-22 03:19:51 +00:00
ui_box *ScrollableBox = UI_MakeBox(ScrollFlags, StrLit("Scrollable Box"));
2023-06-27 14:14:28 +00:00
UI_PushParent(ScrollableBox);
}
}
}
2023-08-22 03:19:51 +00:00
static void UI_ScrollEnd(r32 *X, r32 *Y, ui_box_flags Flags, string Name)
2023-06-27 14:14:28 +00:00
{
b32 AllowOnX = (X != 0);
b32 AllowOnY = (Y != 0);
r32 ScrollAmount = UI_TopFontSize()*4.0f;
2023-06-27 14:14:28 +00:00
ui_box *ScrollableBox = UI_TopParent();
2023-07-19 15:09:41 +00:00
ui_signal ScrollableBoxSignal = UI_SignalFromBox(ScrollableBox);
2023-06-27 14:14:28 +00:00
{
{
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;
*X = EndOffset;
}
else
{
for(platform_event *Event = UI_EventList()->First;
Event != 0;
Event = Event->Next)
{
if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.x != 0)
{
*X -= Event->Scroll.x*ScrollAmount;
Platform_ConsumeEvent(UI_EventList(), Event);
}
}
2023-06-27 14:14:28 +00:00
}
}
}
*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);
2023-09-05 17:50:49 +00:00
r32 ViewHeight = DimOfRange(ScrollableBox->Parent->Parent->Rect).y;//UI_CalculateBoxSize(ScrollableBox->Parent->Parent, Axis2_Y);
2023-06-27 14:14:28 +00:00
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;
*Y = EndOffset;
}
else
{
for(platform_event *Event = UI_EventList()->First;
Event != 0;
Event = Event->Next)
{
if(Event->Type == PlatformEvent_MouseScroll && Event->Scroll.y != 0)
{
*Y -= Event->Scroll.y*ScrollAmount;
Platform_ConsumeEvent(UI_EventList(), Event);
}
}
2023-06-27 14:14:28 +00:00
}
}
}
*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();
2023-08-22 03:19:51 +00:00
}
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);
}
2023-06-17 17:00:55 +00:00
}