Implemented variable sized row specifications
This commit is contained in:
parent
50b6980bec
commit
296472a588
|
@ -200,39 +200,86 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff
|
||||||
{
|
{
|
||||||
ui_InterfaceReset(&State->Interface);
|
ui_InterfaceReset(&State->Interface);
|
||||||
State->Interface.RenderBuffer = RenderBuffer;
|
State->Interface.RenderBuffer = RenderBuffer;
|
||||||
|
State->Interface.WindowBounds = Context->WindowBounds;
|
||||||
|
|
||||||
ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("TestRender Layout"));
|
gs_string A = MakeString("TestRender Layout");
|
||||||
|
|
||||||
ui_widget_id Ids[2];
|
ui_PushLayout(&State->Interface, A);
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
ui_column_spec ColumnRules[] = {
|
||||||
|
{ UIColumnSize_Fixed, 128 },
|
||||||
|
{ UIColumnSize_Fill, 0 },
|
||||||
|
{ UIColumnSize_Percent, .5f }
|
||||||
|
};
|
||||||
|
ui_BeginRow(&State->Interface, 3, ColumnRules);
|
||||||
|
|
||||||
gs_string String = MakeString("Select");
|
|
||||||
ui_StartRow(&State->Interface, 2);
|
|
||||||
for (u32 j = 0; j < 2; j++)
|
|
||||||
{
|
{
|
||||||
if (ui_BeginDropdown(&State->Interface, String))
|
ui_Button(&State->Interface, MakeString("B"));
|
||||||
|
ui_Button(&State->Interface, MakeString("B"));
|
||||||
|
ui_Button(&State->Interface, MakeString("B"));
|
||||||
|
}
|
||||||
|
ui_EndRow(&State->Interface);
|
||||||
|
ui_Button(&State->Interface, MakeString("B"));
|
||||||
|
ui_Button(&State->Interface, MakeString("C"));
|
||||||
|
#elif 0
|
||||||
|
ui_PushLayout(&State->Interface, MakeString("Outer"));
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < State->PanelSystem.PanelDefsCount; i++)
|
for (u32 i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
panel_definition Def = State->PanelSystem.PanelDefs[i];
|
ui_Button(&State->Interface, MakeString("A"));
|
||||||
gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
|
|
||||||
if (ui_Button(&State->Interface, DefName))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ui_PopLayout(&State->Interface);
|
||||||
|
|
||||||
|
ui_BeginRow(&State->Interface, 2);
|
||||||
|
{
|
||||||
|
ui_PushLayout(&State->Interface, MakeString("TestLayout"));
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
ui_Button(&State->Interface, MakeString("TestButon"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui_PopLayout(&State->Interface);
|
||||||
|
|
||||||
|
ui_PushLayout(&State->Interface, MakeString("TestLayout"));
|
||||||
|
{
|
||||||
|
ui_Button(&State->Interface, MakeString("TestButon"));
|
||||||
|
TestToggle = ui_Toggle(&State->Interface, MakeString("Toggle"), TestToggle);
|
||||||
|
TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max);
|
||||||
|
if (ui_BeginDropdown(&State->Interface, MakeString("TestDropdown")))
|
||||||
|
{
|
||||||
|
ui_Button(&State->Interface, MakeString("TestButon"));
|
||||||
|
ui_Button(&State->Interface, MakeString("TestButon"));
|
||||||
|
ui_Button(&State->Interface, MakeString("TestButon"));
|
||||||
}
|
}
|
||||||
ui_EndDropdown(&State->Interface);
|
ui_EndDropdown(&State->Interface);
|
||||||
}
|
}
|
||||||
ui_EndRow(&State->Interface);
|
|
||||||
TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("Test Slider"), TestSlider_Value, TestSlider_Min, TestSlider_Max);
|
|
||||||
|
|
||||||
TestToggle = ui_Toggle(&State->Interface, MakeString("test toggle"), TestToggle);
|
|
||||||
|
|
||||||
ui_Button(&State->Interface, MakeString("Hello"));
|
|
||||||
|
|
||||||
ui_PopLayout(&State->Interface);
|
ui_PopLayout(&State->Interface);
|
||||||
|
}
|
||||||
|
ui_EndRow(&State->Interface);
|
||||||
|
|
||||||
Assert(!ui_WidgetIdsEqual(Ids[0], Ids[1]));
|
ui_PushLayout(&State->Interface, MakeString("Outer"));
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
ui_Button(&State->Interface, MakeString("B"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui_PopLayout(&State->Interface);
|
||||||
|
#else
|
||||||
|
ui_BeginList(&State->Interface, MakeString("Test List"), 10);
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
ui_Button(&State->Interface, MakeString("Option"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui_EndList(&State->Interface);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
ui_PopLayout(&State->Interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
internal void
|
||||||
|
@ -243,9 +290,6 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
TestRender(State, Context, RenderBuffer);
|
TestRender(State, Context, RenderBuffer);
|
||||||
//ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer);
|
|
||||||
//Assert(ui_WidgetIdsEqual(IdOne, IdTwo));
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
ui_InterfaceReset(&State->Interface);
|
ui_InterfaceReset(&State->Interface);
|
||||||
State->Interface.RenderBuffer = RenderBuffer;
|
State->Interface.RenderBuffer = RenderBuffer;
|
||||||
|
|
|
@ -608,7 +608,7 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan
|
||||||
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout"));
|
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout"));
|
||||||
|
|
||||||
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
|
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
|
||||||
ui_StartRow(&State->Interface, 4);
|
ui_BeginRow(&State->Interface, 4);
|
||||||
{
|
{
|
||||||
if (ui_Button(Interface, MakeString("Pause")))
|
if (ui_Button(Interface, MakeString("Pause")))
|
||||||
{
|
{
|
||||||
|
@ -796,7 +796,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende
|
||||||
|
|
||||||
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]);
|
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]);
|
||||||
|
|
||||||
ui_StartRow(&State->Interface, 2);
|
ui_BeginRow(&State->Interface, 2);
|
||||||
{
|
{
|
||||||
ui_Label(Interface, MakeString("Active Animation"));
|
ui_Label(Interface, MakeString("Active Animation"));
|
||||||
if (ui_BeginDropdown(Interface, ActiveAnim->Name))
|
if (ui_BeginDropdown(Interface, ActiveAnim->Name))
|
||||||
|
|
|
@ -52,7 +52,6 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
|
||||||
// Fill in alternating color rows for the backgrounds
|
// Fill in alternating color rows for the backgrounds
|
||||||
for (u32 Line = 0; Line < LineCount; Line++)
|
for (u32 Line = 0; Line < LineCount; Line++)
|
||||||
{
|
{
|
||||||
//LineBounds[Line] = ui_ReserveElementBounds(Layout);
|
|
||||||
v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line);
|
v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line);
|
||||||
ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor);
|
ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,13 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb
|
||||||
char Backbuffer[256];
|
char Backbuffer[256];
|
||||||
gs_string String = MakeString(Backbuffer, 0, 256);
|
gs_string String = MakeString(Backbuffer, 0, 256);
|
||||||
|
|
||||||
r32 ColumnWidths[] = {256, 128, 128, 128, 128};
|
ui_column_spec ColumnWidths[] = {
|
||||||
ui_StartRow(Interface, 5, &ColumnWidths[0]);
|
{ UIColumnSize_Fixed, 256 },
|
||||||
|
{ UIColumnSize_Fixed, 128 },
|
||||||
|
{ UIColumnSize_Fixed, 128 },
|
||||||
|
{ UIColumnSize_Fixed, 128 },
|
||||||
|
{ UIColumnSize_Fixed, 128 }};
|
||||||
|
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
|
||||||
{
|
{
|
||||||
ui_Label(Interface, MakeString("Procedure"));
|
ui_Label(Interface, MakeString("Procedure"));
|
||||||
ui_Label(Interface, MakeString("% Frame"));
|
ui_Label(Interface, MakeString("% Frame"));
|
||||||
|
@ -112,7 +117,7 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb
|
||||||
{
|
{
|
||||||
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
|
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
|
||||||
|
|
||||||
ui_StartRow(Interface, 5, &ColumnWidths[0]);
|
ui_BeginRow(Interface, 5, &ColumnWidths[0]);
|
||||||
{
|
{
|
||||||
PrintF(&String, "%S", NameEntry.Name);
|
PrintF(&String, "%S", NameEntry.Name);
|
||||||
ui_Label(Interface, String);
|
ui_Label(Interface, String);
|
||||||
|
@ -181,7 +186,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
|
||||||
|
|
||||||
ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout"));
|
ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout"));
|
||||||
|
|
||||||
ui_StartRow(&State->Interface, 4);
|
ui_BeginRow(&State->Interface, 4);
|
||||||
{
|
{
|
||||||
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
|
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
|
||||||
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
|
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
|
||||||
|
@ -194,7 +199,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
|
||||||
|
|
||||||
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
|
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
|
||||||
// be removed, or used for something else
|
// be removed, or used for something else
|
||||||
ui_ReserveElementBounds(Layout);
|
ui_ReserveBounds(Layout, true);
|
||||||
|
|
||||||
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
|
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
|
||||||
{
|
{
|
||||||
|
@ -203,7 +208,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
|
||||||
}
|
}
|
||||||
ui_EndRow(&State->Interface);
|
ui_EndRow(&State->Interface);
|
||||||
|
|
||||||
ui_StartRow(&State->Interface, 8);
|
ui_BeginRow(&State->Interface, 8);
|
||||||
{
|
{
|
||||||
if (ui_Button(&State->Interface, MakeString("Scope View")))
|
if (ui_Button(&State->Interface, MakeString("Scope View")))
|
||||||
{
|
{
|
||||||
|
|
|
@ -106,7 +106,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
||||||
State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
|
State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f };
|
||||||
State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f };
|
State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f };
|
||||||
State->Interface.Style.Margin = v2{5, 5};
|
State->Interface.Style.Margin = v2{5, 5};
|
||||||
State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface);
|
State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface) + (2 * State->Interface.Style.Margin.y);
|
||||||
|
|
||||||
State->Interface.WidgetsCountMax = 4096;
|
State->Interface.WidgetsCountMax = 4096;
|
||||||
State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax);
|
State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax);
|
||||||
|
|
|
@ -199,6 +199,13 @@ enum ui_layout_direction
|
||||||
{
|
{
|
||||||
LayoutDirection_TopDown,
|
LayoutDirection_TopDown,
|
||||||
LayoutDirection_BottomUp,
|
LayoutDirection_BottomUp,
|
||||||
|
LayoutDirection_Inherit,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ui_column
|
||||||
|
{
|
||||||
|
r32 XMin;
|
||||||
|
r32 XMax;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ui_widget
|
struct ui_widget
|
||||||
|
@ -225,10 +232,9 @@ struct ui_widget
|
||||||
|
|
||||||
ui_layout_direction FillDirection;
|
ui_layout_direction FillDirection;
|
||||||
|
|
||||||
b32 DrawHorizontal;
|
ui_column* Columns;
|
||||||
u32 ColumnsMax;
|
|
||||||
r32* ColumnWidths;
|
|
||||||
u32 ColumnsCount;
|
u32 ColumnsCount;
|
||||||
|
u32 ColumnsFilled;
|
||||||
|
|
||||||
// NOTE(pjs): I'm not sure this will stay but
|
// NOTE(pjs): I'm not sure this will stay but
|
||||||
// its here so that when we end things like a dropdown,
|
// its here so that when we end things like a dropdown,
|
||||||
|
@ -278,7 +284,10 @@ struct ui_widget_retained_state
|
||||||
struct ui_interface
|
struct ui_interface
|
||||||
{
|
{
|
||||||
interface_config Style;
|
interface_config Style;
|
||||||
|
|
||||||
mouse_state Mouse;
|
mouse_state Mouse;
|
||||||
|
rect2 WindowBounds;
|
||||||
|
|
||||||
render_command_buffer* RenderBuffer;
|
render_command_buffer* RenderBuffer;
|
||||||
|
|
||||||
ui_widget* Widgets;
|
ui_widget* Widgets;
|
||||||
|
@ -325,6 +334,28 @@ ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_WidgetSetFlag(ui_widget* Widget, u64 Flag)
|
||||||
|
{
|
||||||
|
u64 Value = ((u64)1 << Flag);
|
||||||
|
Widget->Flags = Widget->Flags | Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_WidgetClearFlag(ui_widget* Widget, u64 Flag)
|
||||||
|
{
|
||||||
|
u64 Value = ((u64)1 << Flag);
|
||||||
|
Widget->Flags = Widget->Flags & ~Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool
|
||||||
|
ui_WidgetIsFlagSet(ui_widget Widget, u64 Flag)
|
||||||
|
{
|
||||||
|
u64 Value = ((u64)1 << Flag);
|
||||||
|
bool Result = (Widget.Flags & Value);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
internal ui_widget_retained_state*
|
internal ui_widget_retained_state*
|
||||||
ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id)
|
ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id)
|
||||||
{
|
{
|
||||||
|
@ -374,21 +405,7 @@ ui_CreateWidget(ui_interface* Interface, gs_string String)
|
||||||
Result->ChildrenRoot = 0;
|
Result->ChildrenRoot = 0;
|
||||||
Result->ChildrenHead = 0;
|
Result->ChildrenHead = 0;
|
||||||
Result->Flags = 0;
|
Result->Flags = 0;
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void
|
|
||||||
ui_WidgetSetFlag(ui_widget* Widget, u64 Flag)
|
|
||||||
{
|
|
||||||
u64 Value = ((u64)1 << Flag);
|
|
||||||
Widget->Flags = Widget->Flags | Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool
|
|
||||||
ui_WidgetIsFlagSet(ui_widget Widget, u64 Flag)
|
|
||||||
{
|
|
||||||
u64 Value = ((u64)1 << Flag);
|
|
||||||
bool Result = (Widget.Flags & Value);
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,37 +423,146 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect)
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
|
|
||||||
internal ui_widget*
|
static rect2
|
||||||
ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name)
|
ui_ReserveBounds(ui_widget* Widget, bool Inset)
|
||||||
{
|
{
|
||||||
ui_widget* Result = ui_CreateWidget(Interface, Name);
|
Assert(Widget->ColumnsCount > 0);
|
||||||
//ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline);
|
rect2 Bounds = {0};
|
||||||
|
u32 ColumnIndex = Widget->ChildCount % Widget->ColumnsCount;
|
||||||
|
|
||||||
Result->Bounds = Bounds;
|
ui_column Column = Widget->Columns[ColumnIndex];
|
||||||
Result->Margin = Interface->Style.Margin;
|
Bounds.Min.x = Column.XMin;
|
||||||
Result->RowHeight = Interface->Style.RowHeight;
|
Bounds.Min.y = Widget->RowYAt;
|
||||||
Result->FillDirection = FillDir;
|
Bounds.Max.x = Column.XMax;
|
||||||
|
Bounds.Max.y = Bounds.Min.y + Widget->RowHeight;
|
||||||
|
|
||||||
switch(FillDir)
|
if (Inset)
|
||||||
|
{
|
||||||
|
Bounds.Min.x += Widget->Margin.x;
|
||||||
|
Bounds.Min.y += Widget->Margin.y;
|
||||||
|
Bounds.Max.x -= Widget->Margin.x;
|
||||||
|
Bounds.Max.y -= Widget->Margin.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_CommitBounds(ui_widget* Parent, rect2 Bounds)
|
||||||
|
{
|
||||||
|
u32 ColumnIndex = Parent->ChildCount % Parent->ColumnsCount;
|
||||||
|
if (ColumnIndex == 0)
|
||||||
|
{
|
||||||
|
switch (Parent->FillDirection)
|
||||||
{
|
{
|
||||||
case LayoutDirection_BottomUp:
|
case LayoutDirection_BottomUp:
|
||||||
{
|
{
|
||||||
Result->RowYAt = Bounds.Min.y + Result->Margin.y;
|
Parent->RowYAt = Bounds.Max.y;
|
||||||
}break;
|
}break;
|
||||||
|
|
||||||
case LayoutDirection_TopDown:
|
case LayoutDirection_TopDown:
|
||||||
{
|
{
|
||||||
Result->RowYAt = Bounds.Max.y - (Result->RowHeight + Result->Margin.y);
|
Parent->RowYAt = Bounds.Min.y - Parent->RowHeight;
|
||||||
}break;
|
}break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_ExpandParentToFit(ui_widget* Widget)
|
||||||
|
{
|
||||||
|
ui_widget* Parent = Widget->Parent;
|
||||||
|
switch (Widget->FillDirection)
|
||||||
|
{
|
||||||
|
case LayoutDirection_TopDown:
|
||||||
|
{
|
||||||
|
Parent->Bounds.Min.y = Min(Parent->Bounds.Min.y, Widget->Bounds.Min.y - Parent->Margin.y);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case LayoutDirection_BottomUp:
|
||||||
|
{
|
||||||
|
Parent->Bounds.Max.y = Max(Parent->Bounds.Max.y, Widget->Bounds.Max.y + Parent->Margin.y);
|
||||||
|
}break;
|
||||||
|
|
||||||
|
InvalidDefaultCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_WidgetCreateColumns(ui_widget* Widget, u32 ColumnsCount, ui_interface* Interface)
|
||||||
|
{
|
||||||
|
Widget->Columns = PushArray(Interface->PerFrameMemory, ui_column, ColumnsCount);
|
||||||
|
Widget->ColumnsCount = ColumnsCount;
|
||||||
|
Widget->ColumnsFilled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_WidgetInitUniformColumns(ui_widget* Widget)
|
||||||
|
{
|
||||||
|
r32 CurrentRowWidth = Rect2Width(Widget->Bounds);
|
||||||
|
r32 ColumnWidth = CurrentRowWidth / Widget->ColumnsCount;
|
||||||
|
for (u32 i = 0; i < Widget->ColumnsCount; i++)
|
||||||
|
{
|
||||||
|
ui_column* Column = Widget->Columns + i;
|
||||||
|
Column->XMin = Widget->Bounds.Min.x + (ColumnWidth * i);
|
||||||
|
Column->XMax = Column->XMin + ColumnWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal ui_widget*
|
||||||
|
ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, gs_string Name, ui_layout_direction FillDir = LayoutDirection_Inherit)
|
||||||
|
{
|
||||||
|
ui_widget* Result = ui_CreateWidget(Interface, Name);
|
||||||
|
ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline);
|
||||||
|
|
||||||
|
Result->Bounds = Bounds;
|
||||||
|
Result->Margin = Interface->Style.Margin;
|
||||||
|
Result->RowHeight = Interface->Style.RowHeight;
|
||||||
|
|
||||||
|
// Single Column Layout
|
||||||
|
ui_WidgetCreateColumns(Result, 1, Interface);
|
||||||
|
ui_WidgetInitUniformColumns(Result);
|
||||||
|
|
||||||
|
if (FillDir == LayoutDirection_Inherit && Result->Parent != 0)
|
||||||
|
{
|
||||||
|
Result->FillDirection = Result->Parent->FillDirection;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Result->FillDirection = FillDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(Result->FillDirection)
|
||||||
|
{
|
||||||
|
case LayoutDirection_BottomUp:
|
||||||
|
{
|
||||||
|
Result->RowYAt = Bounds.Min.y;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case LayoutDirection_TopDown:
|
||||||
|
{
|
||||||
|
Result->RowYAt = Bounds.Max.y - Result->RowHeight;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
InvalidDefaultCase;
|
||||||
|
}
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ui_widget*
|
||||||
|
ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name)
|
||||||
|
{
|
||||||
|
ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, Name, FillDir);
|
||||||
|
SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result);
|
||||||
|
Interface->ActiveLayout = Result;
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
static ui_widget*
|
static ui_widget*
|
||||||
ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name)
|
ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name)
|
||||||
{
|
{
|
||||||
ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name);
|
ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, Name, FillDir);
|
||||||
|
|
||||||
if (Interface->DrawOrderRoot)
|
if (Interface->DrawOrderRoot)
|
||||||
{
|
{
|
||||||
|
@ -453,124 +579,178 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir
|
||||||
}
|
}
|
||||||
|
|
||||||
static ui_widget*
|
static ui_widget*
|
||||||
ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name)
|
ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true)
|
||||||
{
|
{
|
||||||
ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name);
|
rect2 Bounds = {};
|
||||||
SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result);
|
ui_layout_direction Direction = LayoutDirection_TopDown;
|
||||||
Interface->ActiveLayout = Result;
|
if (Interface->ActiveLayout)
|
||||||
return Result;
|
{
|
||||||
|
Bounds = ui_ReserveBounds(Interface->ActiveLayout, Inset);
|
||||||
|
Direction = Interface->ActiveLayout->FillDirection;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Bounds.Min.x = Interface->WindowBounds.Min.x;
|
||||||
|
Bounds.Min.y = Interface->WindowBounds.Max.y;
|
||||||
|
Bounds.Max.x = Interface->WindowBounds.Max.x;
|
||||||
|
Bounds.Max.y = Interface->WindowBounds.Max.y;
|
||||||
|
|
||||||
|
if (Inset)
|
||||||
|
{
|
||||||
|
Bounds.Min.x += Interface->Style.Margin.x;
|
||||||
|
Bounds.Max.x -= Interface->Style.Margin.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
Direction = LayoutDirection_TopDown;
|
||||||
|
}
|
||||||
|
return ui_PushLayout(Interface, Bounds, Direction, Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_ExpandToFitChildren(ui_widget* Parent)
|
||||||
|
{
|
||||||
|
v2 Extents = { Parent->Bounds.Max.y, Parent->Bounds.Min.y };
|
||||||
|
for (ui_widget* Child = Parent->ChildrenRoot; Child != 0; Child = Child->Next)
|
||||||
|
{
|
||||||
|
Extents.x = Min(Extents.x, Child->Bounds.Min.y);
|
||||||
|
Extents.y = Max(Extents.y, Child->Bounds.Max.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(Parent->FillDirection)
|
||||||
|
{
|
||||||
|
case LayoutDirection_BottomUp:
|
||||||
|
{
|
||||||
|
Parent->Bounds.Max.y = Extents.y + Parent->Margin.y;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case LayoutDirection_TopDown:
|
||||||
|
{
|
||||||
|
Parent->Bounds.Min.y = Extents.x - Parent->Margin.y;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
InvalidDefaultCase;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ui_PopLayout(ui_interface* Interface)
|
ui_PopLayout(ui_interface* Interface)
|
||||||
{
|
{
|
||||||
Assert(Interface->ActiveLayout != 0);
|
Assert(Interface->ActiveLayout != 0);
|
||||||
|
|
||||||
|
ui_widget* Layout = Interface->ActiveLayout;
|
||||||
|
ui_ExpandToFitChildren(Layout);
|
||||||
|
|
||||||
Interface->ActiveLayout = Interface->ActiveLayout->Parent;
|
Interface->ActiveLayout = Interface->ActiveLayout->Parent;
|
||||||
|
|
||||||
|
// NOTE(pjs): This indicates that the parent layout should
|
||||||
|
// expand to fit the layout that we just popped
|
||||||
|
if (Interface->ActiveLayout != 0 &&
|
||||||
|
Interface->ActiveLayout->ChildrenHead == Layout)
|
||||||
|
{
|
||||||
|
ui_CommitBounds(Interface->ActiveLayout, Layout->Bounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 0)
|
ui_BeginRow(ui_interface* Interface, u32 ColumnsMax)
|
||||||
{
|
{
|
||||||
Interface->ActiveLayout->DrawHorizontal = true;
|
ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false);
|
||||||
Interface->ActiveLayout->ColumnsMax = ColumnsMax;
|
ui_WidgetCreateColumns(Layout, ColumnsMax, Interface);
|
||||||
Interface->ActiveLayout->ColumnWidths = 0;
|
ui_WidgetInitUniformColumns(Layout);
|
||||||
Interface->ActiveLayout->ColumnsCount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
enum ui_column_size_rule
|
||||||
ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths)
|
|
||||||
{
|
{
|
||||||
Interface->ActiveLayout->DrawHorizontal = true;
|
UIColumnSize_Fixed,
|
||||||
Interface->ActiveLayout->ColumnsMax = ColumnsMax;
|
UIColumnSize_Percent,
|
||||||
Interface->ActiveLayout->ColumnWidths = ColumnWidths;
|
UIColumnSize_Fill,
|
||||||
Interface->ActiveLayout->ColumnsCount = 0;
|
};
|
||||||
|
|
||||||
|
struct ui_column_spec
|
||||||
|
{
|
||||||
|
ui_column_size_rule Rule;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
r32 Width;
|
||||||
|
r32 Percent;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules)
|
||||||
|
{
|
||||||
|
ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false);
|
||||||
|
ui_WidgetCreateColumns(Layout, ColumnsMax, Interface);
|
||||||
|
|
||||||
|
// First Pass, determine widths of each column, and how much space is left to be divided by the fill columns
|
||||||
|
r32 RowWidth = Rect2Width(Layout->Bounds);
|
||||||
|
r32 RemainingSpace = RowWidth;
|
||||||
|
u32 FillColumnsCount = 0;
|
||||||
|
for (u32 i = 0; i < Layout->ColumnsCount; i++)
|
||||||
|
{
|
||||||
|
ui_column_spec Spec = ColumnRules[i];
|
||||||
|
ui_column* Column = Layout->Columns + i;
|
||||||
|
|
||||||
|
switch (Spec.Rule)
|
||||||
|
{
|
||||||
|
case UIColumnSize_Fixed:
|
||||||
|
{
|
||||||
|
Column->XMax = Spec.Width;
|
||||||
|
RemainingSpace -= Column->XMax;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case UIColumnSize_Percent:
|
||||||
|
{
|
||||||
|
Column->XMax = Spec.Percent * RowWidth;
|
||||||
|
RemainingSpace -= Column->XMax;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case UIColumnSize_Fill:
|
||||||
|
{
|
||||||
|
FillColumnsCount += 1;
|
||||||
|
}break;
|
||||||
|
InvalidDefaultCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r32 FillColumnWidth = RemainingSpace / FillColumnsCount;
|
||||||
|
|
||||||
|
// Second Pass, specify the actual XMin and XMax of each column
|
||||||
|
r32 ColumnStartX = Layout->Bounds.Min.x;
|
||||||
|
for (u32 i = 0; i < Layout->ColumnsCount; i++)
|
||||||
|
{
|
||||||
|
ui_column_spec Spec = ColumnRules[i];
|
||||||
|
ui_column* Column = Layout->Columns + i;
|
||||||
|
|
||||||
|
r32 ColumnWidth = 0;
|
||||||
|
switch (Spec.Rule)
|
||||||
|
{
|
||||||
|
case UIColumnSize_Fixed:
|
||||||
|
case UIColumnSize_Percent:
|
||||||
|
{
|
||||||
|
ColumnWidth = Column->XMax;
|
||||||
|
}break;
|
||||||
|
|
||||||
|
case UIColumnSize_Fill:
|
||||||
|
{
|
||||||
|
ColumnWidth = FillColumnWidth;
|
||||||
|
}break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Column->XMin = ColumnStartX ;
|
||||||
|
Column->XMax = Column->XMin + Max(0, ColumnWidth);
|
||||||
|
ColumnStartX = Column->XMax;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ui_EndRow(ui_interface* Interface)
|
ui_EndRow(ui_interface* Interface)
|
||||||
{
|
{
|
||||||
Interface->ActiveLayout->DrawHorizontal = false;
|
ui_PopLayout(Interface);
|
||||||
Interface->ActiveLayout->ColumnWidths = 0;
|
//ui_widget* Layout = Interface->ActiveLayout;
|
||||||
Interface->ActiveLayout->RowYAt -= (Interface->ActiveLayout->RowHeight + Interface->ActiveLayout->Margin.y);
|
//Layout->DrawHorizontal = false;
|
||||||
}
|
//Layout->RowYAt -= (Layout->RowHeight + Layout->Margin.y);
|
||||||
|
|
||||||
static b32
|
|
||||||
ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds)
|
|
||||||
{
|
|
||||||
b32 Result = true;
|
|
||||||
if (!Widget->DrawHorizontal)
|
|
||||||
{
|
|
||||||
Bounds->Min = { Widget->Bounds.Min.x + Widget->Margin.x, Widget->RowYAt };
|
|
||||||
Bounds->Max = { Widget->Bounds.Max.x - Widget->Margin.x, Bounds->Min.y + Widget->RowHeight };
|
|
||||||
|
|
||||||
r32 RowOffset = Widget->RowHeight + Widget->Margin.y;
|
|
||||||
switch (Widget->FillDirection)
|
|
||||||
{
|
|
||||||
case LayoutDirection_BottomUp:
|
|
||||||
{
|
|
||||||
Widget->RowYAt += RowOffset;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
case LayoutDirection_TopDown:
|
|
||||||
{
|
|
||||||
Widget->RowYAt -= RowOffset;
|
|
||||||
}break;
|
|
||||||
|
|
||||||
InvalidDefaultCase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Widget->ColumnsMax > 0)
|
|
||||||
{
|
|
||||||
Assert(Widget->ColumnsCount < Widget->ColumnsMax);
|
|
||||||
if (Widget->ColumnWidths != 0)
|
|
||||||
{
|
|
||||||
v2 Min = {
|
|
||||||
Widget->Bounds.Min.x + Widget->Margin.x,
|
|
||||||
Widget->RowYAt
|
|
||||||
};
|
|
||||||
for (u32 i = 0; i < Widget->ColumnsCount; i++)
|
|
||||||
{
|
|
||||||
Min.x += Widget->ColumnWidths[i];
|
|
||||||
}
|
|
||||||
Bounds->Min = Min;
|
|
||||||
Bounds->Max = Bounds->Min + v2{
|
|
||||||
Widget->ColumnWidths[Widget->ColumnsCount] - Widget->Margin.x,
|
|
||||||
Widget->RowHeight
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r32 ElementWidth = Rect2Width(Widget->Bounds) / Widget->ColumnsMax;
|
|
||||||
Bounds->Min = {
|
|
||||||
Widget->Bounds.Min.x + (ElementWidth * Widget->ColumnsCount) + Widget->Margin.x,
|
|
||||||
Widget->RowYAt
|
|
||||||
};
|
|
||||||
Bounds->Max = {
|
|
||||||
Bounds->Min.x + ElementWidth - (Widget->Margin.x * 2),
|
|
||||||
Bounds->Min.y + Widget->RowHeight
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Widget->ColumnsCount++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Result = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static rect2
|
|
||||||
ui_ReserveElementBounds(ui_widget* Layout)
|
|
||||||
{
|
|
||||||
rect2 Bounds = {0};
|
|
||||||
if (!ui_TryReserveElementBounds(Layout, &Bounds))
|
|
||||||
{
|
|
||||||
InvalidCodePath;
|
|
||||||
}
|
|
||||||
return Bounds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static rect2
|
static rect2
|
||||||
|
@ -578,10 +758,6 @@ ui_LayoutRemaining(ui_widget Layout)
|
||||||
{
|
{
|
||||||
rect2 Result = Layout.Bounds;
|
rect2 Result = Layout.Bounds;
|
||||||
Result.Max.y = Layout.RowYAt;
|
Result.Max.y = Layout.RowYAt;
|
||||||
if (Layout.DrawHorizontal)
|
|
||||||
{
|
|
||||||
Result.Max.y -= Layout.RowHeight;
|
|
||||||
}
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,20 +801,17 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Assert(Widget->Parent != 0);
|
||||||
|
ui_CommitBounds(Widget->Parent, Widget->Bounds);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ui_eval_result
|
internal ui_eval_result
|
||||||
ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget)
|
ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget)
|
||||||
{
|
{
|
||||||
rect2 Bounds = {0};
|
|
||||||
ui_widget* Layout = Interface->ActiveLayout;
|
ui_widget* Layout = Interface->ActiveLayout;
|
||||||
if (!ui_TryReserveElementBounds(Layout, &Bounds))
|
rect2 Bounds = ui_ReserveBounds(Layout, true);
|
||||||
{
|
|
||||||
// TODO(pjs): This isn't invalid, but Idk when we'd hit this case yet
|
|
||||||
InvalidCodePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ui_EvaluateWidget(Interface, Widget, Bounds);
|
return ui_EvaluateWidget(Interface, Widget, Bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,8 +954,8 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E
|
||||||
r32 ParentLayoutMaxY = ParentLayout.Bounds.Max.y;
|
r32 ParentLayoutMaxY = ParentLayout.Bounds.Max.y;
|
||||||
Direction = LayoutDirection_BottomUp;
|
Direction = LayoutDirection_BottomUp;
|
||||||
MenuBounds = rect2{
|
MenuBounds = rect2{
|
||||||
v2{ Widget->Bounds.Min.x, Widget->Bounds.Max.y },
|
v2{ Widget->Bounds.Min.x - ParentLayout.Margin.x, Widget->Bounds.Max.y },
|
||||||
v2{ Widget->Bounds.Max.x, ParentLayoutMaxY }
|
v2{ Widget->Bounds.Max.x + ParentLayout.Margin.x, ParentLayoutMaxY }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -790,14 +963,15 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E
|
||||||
r32 ParentLayoutMinY = ParentLayout.Bounds.Min.y;
|
r32 ParentLayoutMinY = ParentLayout.Bounds.Min.y;
|
||||||
Direction = LayoutDirection_TopDown;
|
Direction = LayoutDirection_TopDown;
|
||||||
MenuBounds = rect2{
|
MenuBounds = rect2{
|
||||||
v2{ Widget->Bounds.Min.x, ParentLayoutMinY },
|
v2{ Widget->Bounds.Min.x - ParentLayout.Margin.x, ParentLayoutMinY },
|
||||||
v2{ Widget->Bounds.Max.x, Widget->Bounds.Min.y }
|
v2{ Widget->Bounds.Max.x + ParentLayout.Margin.x, Widget->Bounds.Min.y }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout"));
|
ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout"));
|
||||||
Layout->Margin.y = 0;
|
Layout->Margin.y = 0;
|
||||||
Layout->WidgetReference = Widget->Id;
|
Layout->WidgetReference = Widget->Id;
|
||||||
|
ui_WidgetClearFlag(Layout, UIWidgetFlag_DrawOutline);
|
||||||
}
|
}
|
||||||
|
|
||||||
return State->Value;
|
return State->Value;
|
||||||
|
@ -913,6 +1087,19 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value)
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows)
|
||||||
|
{
|
||||||
|
ui_widget* Layout = ui_PushLayout(Interface, Text);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void
|
||||||
|
ui_EndList(ui_interface* Interface)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// OLD
|
// OLD
|
||||||
|
|
Loading…
Reference in New Issue