Pretty big ui overhaul.

This commit is contained in:
PS 2020-11-07 22:54:59 -08:00
parent 723458c491
commit d5be2a2de8
9 changed files with 531 additions and 200 deletions

View File

@ -84,8 +84,12 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB
PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderOrthographic(RenderBuffer, State->WindowBounds);
PushRenderClearScreen(RenderBuffer); PushRenderClearScreen(RenderBuffer);
ui_InterfaceReset(&State->Interface);
State->Interface.RenderBuffer = RenderBuffer; State->Interface.RenderBuffer = RenderBuffer;
ui_layout Layout = ui_CreateLayout(&State->Interface, Context->WindowBounds);
ui_PushLayout(&State->Interface, Layout);
DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context);
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
@ -97,6 +101,66 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB
} }
} }
ui_PopLayout(&State->Interface);
// Draw the Interface
for (u32 i = 0; i < State->Interface.WidgetsCount; i++)
{
ui_widget Widget = State->Interface.Widgets[i];
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground))
{
v4 Color = State->Interface.Style.ButtonColor_Inactive;
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget))
{
Color = State->Interface.Style.ButtonColor_Active;
}
if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget))
{
Color = State->Interface.Style.ButtonColor_Selected;
}
PushRenderQuad2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Color);
}
if (Widget.String.Length > 0)
{
v4 Color = State->Interface.Style.TextColor;
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer,
Widget.String.Length,
State->Interface.Style.Font->BitmapMemory,
State->Interface.Style.Font->BitmapTextureHandle,
State->Interface.Style.Font->BitmapWidth,
State->Interface.Style.Font->BitmapHeight,
State->Interface.Style.Font->BitmapBytesPerPixel,
State->Interface.Style.Font->BitmapStride);
v2 RegisterPosition = Widget.Bounds.Min + State->Interface.Style.Margin;
switch (Widget.Alignment)
{
case Align_Left:
{
RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color);
}break;
case Align_Right:
{
RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color);
}break;
InvalidDefaultCase;
}
}
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline))
{
// TODO(pjs): replace these with values from the style
r32 Thickness = 1.0f;
v4 Color = WhiteV4;
PushRenderBoundingBox2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Thickness, Color);
}
}
Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext);
Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue);

View File

@ -388,42 +388,19 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB
rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23}); rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23});
if (Panel->PanelSelectionMenuOpen) if (ui_BeginDropdown(&State->Interface, MakeString("Select"), PanelSelectBtnBounds))
{ {
rect2 ButtonBounds = MakeRect2MinDim(v2{ PanelSelectBtnBounds.Min.x, FooterBounds.Max.y }, v2{ 100, 25 });
rect2 MenuBounds = rect2
{
ButtonBounds.Min,
v2{
ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * State->PanelSystem.PanelDefsCount)
},
};
if (ui_MouseClickedRect(State->Interface, MenuBounds))
{
Panel->PanelSelectionMenuOpen = false;
}
for (s32 i = 0; i < GlobalPanelDefsCount; i++) for (s32 i = 0; i < GlobalPanelDefsCount; i++)
{ {
panel_definition Def = State->PanelSystem.PanelDefs[i]; panel_definition Def = State->PanelSystem.PanelDefs[i];
gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength);
if (ui_Button(&State->Interface, DefName, ButtonBounds)) if (ui_Button(&State->Interface, DefName))
{ {
Panel_SetType(Panel, &State->PanelSystem, i, State, Context); Panel_SetType(Panel, &State->PanelSystem, i, State, Context);
Panel->PanelSelectionMenuOpen = false;
} }
ButtonBounds = Rect2TranslateY(ButtonBounds, Rect2Height(ButtonBounds));
} }
} }
ui_EndDropdown(&State->Interface);
if (ui_Button(&State->Interface, MakeString("Select"), PanelSelectBtnBounds))
{
Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen;
}
} }
internal void internal void

View File

@ -36,10 +36,6 @@ struct panel
panel_split_direction SplitDirection; panel_split_direction SplitDirection;
r32 SplitPercent; r32 SplitPercent;
// TODO(Peter): This REALLY doesn't want to live here
// Probably belongs in a more generalized PanelInterfaceState or something
b32 PanelSelectionMenuOpen;
panel* Parent; panel* Parent;
union{ union{

View File

@ -588,7 +588,8 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
internal void internal void
DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem)
{ {
ui_layout Layout = ui_CreateLayout(*Interface, PanelBounds); ui_layout Layout = ui_CreateLayout(Interface, PanelBounds);
ui_PushLayout(Interface, Layout);
for (s32 i = 0; i < GlobalAnimationClipsCount; i++) for (s32 i = 0; i < GlobalAnimationClipsCount; i++)
{ {
animation_clip Clip = GlobalAnimationClips[i]; animation_clip Clip = GlobalAnimationClips[i];
@ -598,6 +599,7 @@ DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedA
AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem); AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem);
} }
} }
ui_PopLayout(Interface);
} }
internal void internal void
@ -605,34 +607,36 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan
{ {
animation_system* AnimSystem = &State->AnimationSystem; animation_system* AnimSystem = &State->AnimationSystem;
ui_interface* Interface = &State->Interface; ui_interface* Interface = &State->Interface;
ui_layout Layout = ui_CreateLayout(*Interface, Bounds); ui_layout Layout = ui_CreateLayout(Interface, Bounds);
ui_PushLayout(Interface, Layout);
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
ui_StartRow(&Layout, 4); ui_StartRow(&State->Interface, 4);
{ {
if (ui_LayoutButton(Interface, &Layout, MakeString("Pause"))) if (ui_Button(Interface, MakeString("Pause")))
{ {
AnimSystem->TimelineShouldAdvance = false; AnimSystem->TimelineShouldAdvance = false;
} }
if (ui_LayoutButton(Interface, &Layout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4)) if (ui_Button(Interface, MakeString("Play")))
{ {
AnimSystem->TimelineShouldAdvance = true; AnimSystem->TimelineShouldAdvance = true;
} }
if (ui_LayoutButton(Interface, &Layout, MakeString("Stop"))) if (ui_Button(Interface, MakeString("Stop")))
{ {
AnimSystem->TimelineShouldAdvance = false; AnimSystem->TimelineShouldAdvance = false;
AnimSystem->CurrentFrame = 0; AnimSystem->CurrentFrame = 0;
} }
if (ui_LayoutButton(Interface, &Layout, MakeString("Load"))) if (ui_Button(Interface, MakeString("Load")))
{ {
panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); panel* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context);
Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
} }
} }
ui_EndRow(&Layout); ui_EndRow(&State->Interface);
ui_PopLayout(&State->Interface);
} }
internal void internal void
@ -787,7 +791,33 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
internal void internal void
AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context) AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{ {
ui_FillRect(&State->Interface, Bounds, PinkV4); animation_system* AnimSystem = &State->AnimationSystem;
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem);
ui_interface* Interface = &State->Interface;
ui_layout Layout = ui_CreateLayout(Interface, Bounds);
ui_PushLayout(Interface, Layout);
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]);
ui_StartRow(&State->Interface, 2);
{
ui_DrawString(Interface, MakeString("Active Animation"));
if (ui_BeginDropdown(Interface, ActiveAnim->Name))
{
for (u32 i = 0; i < AnimSystem->Animations.Count; i++)
{
animation Animation = AnimSystem->Animations.Values[i];
if (ui_Button(Interface, Animation.Name))
{
AnimSystem->ActiveAnimationIndex = i;
}
}
}
ui_EndDropdown(Interface);
}
ui_EndRow(&State->Interface);
ui_PopLayout(Interface);
} }
internal void internal void
@ -807,7 +837,7 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds); RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds);
rect2 AnimInfoBounds, SelectionInfoBounds; rect2 AnimInfoBounds, SelectionInfoBounds;
RectHSplitAtPercent(InfoBounds, .35f, &AnimInfoBounds, &SelectionInfoBounds); RectHSplitAtPercent(InfoBounds, .65f, &AnimInfoBounds, &SelectionInfoBounds);
{ // Timeline { // Timeline
rect2 LayersPanelBounds, TimeRangePanelBounds; rect2 LayersPanelBounds, TimeRangePanelBounds;

View File

@ -88,15 +88,16 @@ internal void
FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{ {
file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state); file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state);
ui_layout Layout = ui_CreateLayout(State->Interface, PanelBounds); ui_layout Layout = ui_CreateLayout(&State->Interface, PanelBounds);
ui_PushLayout(&State->Interface, Layout);
if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Exit"))) if (ui_Button(&State->Interface, MakeString("Exit")))
{ {
FileView_Exit_(Panel, State, Context); FileView_Exit_(Panel, State, Context);
} }
// Header // Header
ui_LayoutDrawString(&State->Interface, &Layout, FileViewState->WorkingDirectory, v4{0, 1, 0, 1}); ui_DrawString(&State->Interface, FileViewState->WorkingDirectory);
// File Display // File Display
for (u32 i = 0; i < FileViewState->FileNames.Count; i++) for (u32 i = 0; i < FileViewState->FileNames.Count; i++)
@ -121,6 +122,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
} }
} }
ui_PopLayout(&State->Interface);
} }

View File

@ -38,7 +38,9 @@ GSMetaTag(panel_type_hierarchy);
internal void internal void
HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context)
{ {
ui_layout Layout = ui_CreateLayout(State->Interface, PanelBounds); ui_layout Layout = ui_CreateLayout(&State->Interface, PanelBounds);
ui_PushLayout(&State->Interface, Layout);
gs_string TempString = PushString(State->Transient, 256); gs_string TempString = PushString(State->Transient, 256);
u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1; u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1;
u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count); u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count);
@ -57,16 +59,15 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
assembly Assembly = State->Assemblies.Values[AssemblyIndex]; assembly Assembly = State->Assemblies.Values[AssemblyIndex];
PrintF(&TempString, "%S", Assembly.Name); PrintF(&TempString, "%S", Assembly.Name);
ui_layout ItemLayout = ui_CreateLayout(State->Interface, LineBounds[AssemblyIndex]); ui_StartRow(&State->Interface, 2);
ui_StartRow(&ItemLayout, 2);
{ {
ui_LayoutDrawString(&State->Interface, &ItemLayout, TempString, State->Interface.Style.TextColor); ui_DrawString(&State->Interface, TempString);
if (ui_LayoutListButton(&State->Interface, &ItemLayout, MakeString("X"), AssemblyIndex)) if (ui_LayoutListButton(&State->Interface, &Layout, MakeString("X"), AssemblyIndex))
{ {
UnloadAssembly(AssemblyIndex, State, Context); UnloadAssembly(AssemblyIndex, State, Context);
} }
} }
ui_EndRow(&ItemLayout); ui_EndRow(&State->Interface);
} }
if (AssembliesToDraw < LineCount) if (AssembliesToDraw < LineCount)
@ -79,6 +80,8 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
} }
} }
ui_PopLayout(&State->Interface);
} }

View File

@ -84,7 +84,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles);
rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32}); rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32});
ui_TextBox(Interface, TextBounds, String, BlackV4, WhiteV4); ui_DrawString(Interface, String, TextBounds);
} }
} }
@ -95,15 +95,15 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debu
gs_string String = MakeString(Backbuffer, 0, 256); gs_string String = MakeString(Backbuffer, 0, 256);
r32 ColumnWidths[] = {256, 128, 128, 128, 128}; r32 ColumnWidths[] = {256, 128, 128, 128, 128};
ui_StartRow(&Layout, 5, &ColumnWidths[0]); ui_StartRow(Interface, 5, &ColumnWidths[0]);
{ {
ui_LayoutDrawString(Interface, &Layout, MakeString("Procedure"), Interface->Style.TextColor); ui_DrawString(Interface, MakeString("Procedure"));
ui_LayoutDrawString(Interface, &Layout, MakeString("% Frame"), Interface->Style.TextColor); ui_DrawString(Interface, MakeString("% Frame"));
ui_LayoutDrawString(Interface, &Layout, MakeString("Seconds"), Interface->Style.TextColor); ui_DrawString(Interface, MakeString("Seconds"));
ui_LayoutDrawString(Interface, &Layout, MakeString("Cycles"), Interface->Style.TextColor); ui_DrawString(Interface, MakeString("Cycles"));
ui_LayoutDrawString(Interface, &Layout, MakeString("Calls"), Interface->Style.TextColor); ui_DrawString(Interface, MakeString("Calls"));
} }
ui_EndRow(&Layout); ui_EndRow(Interface);
for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++)
{ {
@ -112,24 +112,24 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debu
{ {
collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n;
ui_StartRow(&Layout, 5, &ColumnWidths[0]); ui_StartRow(Interface, 5, &ColumnWidths[0]);
{ {
PrintF(&String, "%S", NameEntry.Name); PrintF(&String, "%S", NameEntry.Name);
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); ui_DrawString(Interface, String);
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); ui_DrawString(Interface, String);
PrintF(&String, "%fs", CollatedRecord->TotalSeconds); PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); ui_DrawString(Interface, String);
PrintF(&String, "%dcy", CollatedRecord->TotalCycles); PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); ui_DrawString(Interface, String);
PrintF(&String, "%d", CollatedRecord->CallCount); PrintF(&String, "%d", CollatedRecord->CallCount);
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor); ui_DrawString(Interface, String);
} }
ui_EndRow(&Layout); ui_EndRow(Interface);
} }
} }
} }
@ -179,41 +179,43 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
ui_layout Layout = ui_CreateLayout(State->Interface, ProcListBounds); ui_layout Layout = ui_CreateLayout(&State->Interface, ProcListBounds);
ui_StartRow(&Layout, 4); ui_PushLayout(&State->Interface, Layout);
ui_StartRow(&State->Interface, 4);
{ {
s64 FrameStartCycles = VisibleFrame->FrameStartCycles; s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1; u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1;
PrintF(&String, "Frame %d", CurrentDebugFrame); PrintF(&String, "Frame %d", CurrentDebugFrame);
ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4); ui_DrawString(&State->Interface, String);
PrintF(&String, "Total Cycles: %lld", FrameTotalCycles); PrintF(&String, "Total Cycles: %lld", FrameTotalCycles);
ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4); ui_DrawString(&State->Interface, String);
// 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_ReserveElementBounds(&Layout);
if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Resume Recording"))) if (ui_Button(&State->Interface, MakeString("Resume Recording")))
{ {
GlobalDebugServices->RecordFrames = true; GlobalDebugServices->RecordFrames = true;
} }
} }
ui_EndRow(&Layout); ui_EndRow(&State->Interface);
ui_StartRow(&Layout, 8); ui_StartRow(&State->Interface, 8);
{ {
if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Scope View"))) if (ui_Button(&State->Interface, MakeString("Scope View")))
{ {
GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER;
} }
if (ui_LayoutButton(&State->Interface, &Layout, MakeString("List View"))) if (ui_Button(&State->Interface, MakeString("List View")))
{ {
GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST;
} }
} }
ui_EndRow(&Layout); ui_EndRow(&State->Interface);
if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER) if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER)
{ {
@ -223,6 +225,8 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
{ {
RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory); RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory);
} }
ui_PopLayout(&State->Interface);
} }

View File

@ -103,7 +103,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
State->Interface.Style.PanelBGColors[3] = v4{.6f, .6f, .6f, 1}; State->Interface.Style.PanelBGColors[3] = v4{.6f, .6f, .6f, 1};
State->Interface.Style.ButtonColor_Inactive = BlackV4; State->Interface.Style.ButtonColor_Inactive = BlackV4;
State->Interface.Style.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; State->Interface.Style.ButtonColor_Active = v4{.1f, .1f, .1f, 1};
State->Interface.Style.ButtonColor_Selected = v4{.1f, .1f, .3f, 1}; State->Interface.Style.ButtonColor_Selected = v4{.3f, .3f, .3f, 1};
State->Interface.Style.TextColor = WhiteV4; State->Interface.Style.TextColor = WhiteV4;
State->Interface.Style.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; State->Interface.Style.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f };
State->Interface.Style.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; State->Interface.Style.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f };
@ -112,6 +112,9 @@ INITIALIZE_APPLICATION(InitializeApplication)
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);
State->Interface.WidgetsCountMax = 4096;
State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax);
State->SACN = SACN_Initialize(Context); State->SACN = SACN_Initialize(Context);
State->Camera.FieldOfView = 45.0f; State->Camera.FieldOfView = 45.0f;
@ -119,8 +122,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
State->Camera.Near = .1f; State->Camera.Near = .1f;
State->Camera.Far = 800.0f; State->Camera.Far = 800.0f;
State->Camera.Position = v3{0, 0, 400}; State->Camera.Position = v3{0, 0, 400};
State->Camera.LookAt = v3{0, 0, 0 State->Camera.LookAt = v3{0, 0, 0};
};
State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128); State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128);

View File

@ -5,6 +5,14 @@
// //
#ifndef INTERFACE_H #ifndef INTERFACE_H
// Widget Capabilities
// - string
// - background
// - outline
// - active (mouse is interacting)
// - hot (mouse could be about to interact)
// - retained state - if a toggle is active, or a drop down is open
enum gs_string_alignment enum gs_string_alignment
{ {
Align_Left, Align_Left,
@ -129,7 +137,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col
} }
internal v2 internal v2
Drawgs_stringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, gs_string_alignment Alignment = Align_Left) DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, gs_string_alignment Alignment = Align_Left)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
v2 LowerRight = Position; v2 LowerRight = Position;
@ -180,10 +188,44 @@ Drawgs_stringWithCursor (render_command_buffer* RenderBuffer, gs_string String,
return LowerRight; return LowerRight;
} }
// TODO(pjs): remove the need for htis (go thru and remove code that's in the #else block of #ifdef EXTERNAL_RENDERER s
#define EXTERNAL_RENDERER
enum ui_widget_flag
{
UIWidgetFlag_DrawBackground,
UIWidgetFlag_DrawOutline,
UIWidgetFlag_Clickable,
};
struct ui_widget_id
{
u64 Index;
u64 LayoutId;
};
struct ui_widget
{
ui_widget_id Id;
gs_string String;
gs_string_alignment Alignment;
rect2 Bounds;
u64 Flags;
bool RetainedState;
};
struct ui_eval_result
{
bool Clicked;
};
struct interface_config struct interface_config
{ {
v4 PanelBGColors[4]; v4 PanelBGColors[4];
// TODO(pjs): Turn these into _Default, _Hot, _Active
v4 ButtonColor_Inactive, ButtonColor_Active, ButtonColor_Selected; v4 ButtonColor_Inactive, ButtonColor_Active, ButtonColor_Selected;
v4 TextColor; v4 TextColor;
@ -199,17 +241,38 @@ struct interface_config
r32 RowHeight; r32 RowHeight;
}; };
enum ui_layout_direction
{
LayoutDirection_TopDown,
LayoutDirection_BottomUp,
};
struct ui_layout struct ui_layout
{ {
u64 Id;
rect2 Bounds; rect2 Bounds;
v2 Margin; v2 Margin;
r32 RowHeight; r32 RowHeight;
r32 RowYAt; r32 RowYAt;
ui_layout_direction FillDirection;
b32 DrawHorizontal; b32 DrawHorizontal;
u32 ColumnsMax; u32 ColumnsMax;
r32* ColumnWidths; r32* ColumnWidths;
u32 ColumnsCount; u32 ColumnsCount;
// NOTE(pjs): I'm not sure this will stay but
// its here so that when we end things like a dropdown,
// we can check the retained state of that dropdown
ui_widget_id WidgetReference;
};
struct ui_widget_retained_state
{
ui_widget_id Id;
bool Value;
}; };
struct ui_interface struct ui_interface
@ -217,49 +280,144 @@ struct ui_interface
interface_config Style; interface_config Style;
mouse_state Mouse; mouse_state Mouse;
render_command_buffer* RenderBuffer; render_command_buffer* RenderBuffer;
ui_widget* Widgets;
u64 WidgetsCount;
u64 WidgetsCountMax;
ui_widget_id HotWidget;
ui_widget_id ActiveWidget;
#define LAYOUT_COUNT_MAX 8
ui_layout LayoutStack[LAYOUT_COUNT_MAX];
u64 LayoutStackCount;
u64 LayoutIdAcc;
#define RETAINED_STATE_MAX 128
ui_widget_retained_state RetainedState[RETAINED_STATE_MAX];
u64 RetainedStateCount;
}; };
internal void
ui_InterfaceReset(ui_interface* Interface)
{
Interface->WidgetsCount = 0;
Interface->LayoutStackCount = 0;
Interface->LayoutIdAcc = 0;
}
internal bool
ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B)
{
bool Result = (A.Index == B.Index) && (A.LayoutId == B.LayoutId);
return Result;
}
internal ui_widget_retained_state*
ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id)
{
ui_widget_retained_state* Result = 0;
for (u64 i = 0; i < Interface->RetainedStateCount; i++)
{
if (ui_WidgetIdsEqual(Interface->RetainedState[i].Id, Id))
{
Result = Interface->RetainedState + i;
break;
}
}
return Result;
}
internal ui_widget_retained_state*
ui_CreateRetainedState(ui_interface* Interface, ui_widget_id Id)
{
u64 Index = Interface->RetainedStateCount++;
ui_widget_retained_state* Result = Interface->RetainedState + Index;
Result->Id = Id;
return Result;
}
//
// Interaction
//
internal b32
ui_MouseClickedRect(ui_interface Interface, rect2 Rect)
{
b32 Result = MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState);
Result &= PointIsInRect(Rect, Interface.Mouse.Pos);
return Result;
}
// Layout
static ui_layout static ui_layout
ui_CreateLayout(ui_interface Interface, rect2 Bounds) ui_CreateLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDirection = LayoutDirection_TopDown)
{ {
ui_layout Result = {0}; ui_layout Result = {0};
Result.Bounds = Bounds; Result.Bounds = Bounds;
Result.Margin = Interface.Style.Margin; Result.Margin = Interface->Style.Margin;
Result.RowHeight = Interface.Style.RowHeight; Result.RowHeight = Interface->Style.RowHeight;
Result.RowYAt = Bounds.Max.y - Result.RowHeight; Result.FillDirection = FillDirection;
switch(FillDirection)
{
case LayoutDirection_BottomUp:
{
Result.RowYAt = Bounds.Min.y;
}break;
case LayoutDirection_TopDown:
{
Result.RowYAt = Bounds.Max.y - Result.RowHeight;
}break;
}
Result.Id = ++Interface->LayoutIdAcc;
return Result; return Result;
} }
static void static void
ui_StartRow(ui_layout* Layout, u32 ColumnsMax) ui_PushLayout(ui_interface* Interface, ui_layout Layout)
{ {
Layout->DrawHorizontal = true; Assert(Interface->LayoutStackCount < LAYOUT_COUNT_MAX);
Layout->ColumnsMax = ColumnsMax; Interface->LayoutStack[Interface->LayoutStackCount++] = Layout;
Layout->ColumnWidths = 0;
Layout->ColumnsCount = 0;
} }
static void static void
ui_StartRow(ui_layout* Layout) ui_PopLayout(ui_interface* Interface)
{ {
ui_StartRow(Layout, 0); Assert(Interface->LayoutStackCount > 0);
Interface->LayoutStackCount -= 1;
} }
static void static void
ui_StartRow(ui_layout* Layout, u32 ColumnsMax, r32* ColumnWidths) ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 0)
{ {
Layout->DrawHorizontal = true; u64 LayoutIdx = Interface->LayoutStackCount - 1;
Layout->ColumnsMax = ColumnsMax; Interface->LayoutStack[LayoutIdx].DrawHorizontal = true;
Layout->ColumnWidths = ColumnWidths; Interface->LayoutStack[LayoutIdx].ColumnsMax = ColumnsMax;
Layout->ColumnsCount = 0; Interface->LayoutStack[LayoutIdx].ColumnWidths = 0;
Interface->LayoutStack[LayoutIdx].ColumnsCount = 0;
} }
static void static void
ui_EndRow(ui_layout* Layout) ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths)
{ {
Layout->DrawHorizontal = false; u64 LayoutIdx = Interface->LayoutStackCount - 1;
Layout->ColumnWidths = 0; Interface->LayoutStack[LayoutIdx].DrawHorizontal = true;
Layout->RowYAt -= Layout->RowHeight; Interface->LayoutStack[LayoutIdx].ColumnsMax = ColumnsMax;
Interface->LayoutStack[LayoutIdx].ColumnWidths = ColumnWidths;
Interface->LayoutStack[LayoutIdx].ColumnsCount = 0;
}
static void
ui_EndRow(ui_interface* Interface)
{
u64 LayoutIdx = Interface->LayoutStackCount - 1;
Interface->LayoutStack[LayoutIdx].DrawHorizontal = false;
Interface->LayoutStack[LayoutIdx].ColumnWidths = 0;
Interface->LayoutStack[LayoutIdx].RowYAt -= Interface->LayoutStack[LayoutIdx].RowHeight;
} }
static b32 static b32
@ -270,7 +428,21 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
{ {
Bounds->Min = { Layout->Bounds.Min.x, Layout->RowYAt }; Bounds->Min = { Layout->Bounds.Min.x, Layout->RowYAt };
Bounds->Max = { Layout->Bounds.Max.x, Bounds->Min.y + Layout->RowHeight }; Bounds->Max = { Layout->Bounds.Max.x, Bounds->Min.y + Layout->RowHeight };
Layout->RowYAt -= Layout->RowHeight;
switch (Layout->FillDirection)
{
case LayoutDirection_BottomUp:
{
Layout->RowYAt += Layout->RowHeight;
}break;
case LayoutDirection_TopDown:
{
Layout->RowYAt -= Layout->RowHeight;
}break;
InvalidDefaultCase;
}
} }
else else
{ {
@ -309,14 +481,6 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
return Result; return Result;
} }
static rect2
ui_ReserveTextLineBounds(ui_interface Interface, gs_string Text, ui_layout* Layout)
{
rect2 Bounds = {0};
return Bounds;
}
static rect2 static rect2
ui_ReserveElementBounds(ui_layout* Layout) ui_ReserveElementBounds(ui_layout* Layout)
{ {
@ -340,18 +504,81 @@ ui_LayoutRemaining(ui_layout Layout)
return Result; return Result;
} }
// // Widgets
// Interaction
//
internal b32 internal ui_widget
ui_MouseClickedRect(ui_interface Interface, rect2 Rect) ui_CreateWidget(gs_string String)
{ {
b32 Result = MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState); ui_widget Result = {};
Result &= PointIsInRect(Rect, Interface.Mouse.Pos); Result.String = String;
Result.Alignment = Align_Left;
return Result; 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;
}
internal ui_eval_result
ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds)
{
ui_eval_result Result = {};
Assert(Interface->WidgetsCount < Interface->WidgetsCountMax);
Widget->Id.Index = Interface->WidgetsCount++;
Widget->Id.LayoutId = Interface->LayoutStack[Interface->LayoutStackCount - 1].Id;
Widget->Bounds = Bounds;
Interface->Widgets[Widget->Id.Index] = *Widget;
if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable))
{
if (PointIsInRect(Widget->Bounds, Interface->Mouse.Pos))
{
if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id) && MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState))
{
Result.Clicked = true;
Interface->ActiveWidget = Widget->Id;
}
if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) &&
MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState))
{
Interface->ActiveWidget = {};
}
Interface->HotWidget = Widget->Id;
}
}
return Result;
}
internal ui_eval_result
ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget)
{
rect2 Bounds = {0};
ui_layout* Layout = Interface->LayoutStack + Interface->LayoutStackCount - 1;
if (!ui_TryReserveElementBounds(Layout, &Bounds))
{
// TODO(pjs): This isn't invalid, but Idk when we'd hit this case yet
InvalidCodePath;
}
return ui_EvaluateWidget(Interface, Widget, Bounds);
}
// //
// Drawing Functions // Drawing Functions
// //
@ -376,78 +603,40 @@ ui_OutlineRect(ui_interface* Interface, rect2 Bounds, r32 Thickness, v4 Color)
} }
internal void internal void
ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, v4 Color, gs_string_alignment Alignment = Align_Left) ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(Interface->RenderBuffer, ui_widget Widget = ui_CreateWidget(String);
String.Length, Widget.Bounds = Bounds;
Interface->Style.Font->BitmapMemory, ui_EvaluateWidget(Interface, &Widget);
Interface->Style.Font->BitmapTextureHandle,
Interface->Style.Font->BitmapWidth,
Interface->Style.Font->BitmapHeight,
Interface->Style.Font->BitmapBytesPerPixel,
Interface->Style.Font->BitmapStride);
v2 RegisterPosition = Bounds.Min + Interface->Style.Margin;
if (Alignment == Align_Left)
{
RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Interface->Style.Font, Color);
}
else if (Alignment == Align_Right)
{
RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Interface->Style.Font, Color);
}
else
{
InvalidCodePath;
}
} }
static void internal void
ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, gs_string String, v4 Color, gs_string_alignment Alignment = Align_Left) ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left)
{ {
rect2 Bounds = {0}; DEBUG_TRACK_FUNCTION;
if (!ui_TryReserveElementBounds(Layout, &Bounds)) ui_widget Widget = ui_CreateWidget(String);
{ ui_EvaluateWidget(Interface, &Widget);
// TODO(NAME): Not invalid, just haven't implemented yet.
// This is the case where Layout is in row mode without a fixed number of elements
InvalidCodePath;
}
ui_DrawString(Interface, String, Bounds, Color, Alignment);
}
static void
ui_TextBox(ui_interface* Interface, rect2 Bounds, gs_string Text, v4 BGColor, v4 TextColor)
{
ui_FillRect(Interface, Bounds, BGColor);
ui_DrawString(Interface, Text, Bounds, TextColor);
} }
static b32 static b32
ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds, v4 InactiveColor, v4 HoverColor, v4 ClickedColor) ui_Button(ui_interface* Interface, gs_string Text)
{ {
b32 Pressed = false; ui_widget Widget = ui_CreateWidget(Text);
v4 ButtonBG = InactiveColor; ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable);
if (PointIsInRect(Bounds, Interface->Mouse.Pos)) ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground);
{ ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget);
ButtonBG = HoverColor; return Result.Clicked;
if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState))
{
ButtonBG = ClickedColor;
Pressed = true;
}
}
ui_TextBox(Interface, Bounds, Text, ButtonBG, Interface->Style.TextColor);
return Pressed;
} }
static b32 static b32
ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds) ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds)
{ {
v4 BGColor = Interface->Style.ButtonColor_Inactive; ui_widget Widget = ui_CreateWidget(Text);
v4 HoverColor = Interface->Style.ButtonColor_Active; ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable);
v4 SelectedColor = Interface->Style.ButtonColor_Selected; ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground);
return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget, Bounds);
return Result.Clicked;
} }
struct list_item_colors struct list_item_colors
@ -477,35 +666,19 @@ ui_GetListItemColors(ui_interface* Interface, u32 ListItemIndex)
static b32 static b32
ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex) ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex)
{ {
list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex); ui_widget Widget = ui_CreateWidget(Text);
return ui_Button(Interface, Text, Bounds, Colors.Hover, Colors.Selected, Colors.BGColor); ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground);
} ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable);
// TODO(pjs): Reimplement alternating color backgrounds
static b32 Widget.Bounds = Bounds;
ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, v4 BGColor, v4 HoverColor, v4 SelectColor) ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget);
{ return Result.Clicked;
rect2 ButtonBounds = {0};
if (!ui_TryReserveElementBounds(Layout, &ButtonBounds))
{
ButtonBounds = ui_ReserveTextLineBounds(*Interface, Text, Layout);
}
return ui_Button(Interface, Text, ButtonBounds, BGColor, HoverColor, SelectColor);
}
static b32
ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text)
{
v4 BGColor = Interface->Style.ButtonColor_Inactive;
v4 HoverColor = Interface->Style.ButtonColor_Active;
v4 SelectedColor = Interface->Style.ButtonColor_Selected;
return ui_LayoutButton(Interface, Layout, Text, BGColor, HoverColor, SelectedColor);
} }
static b32 static b32
ui_LayoutListButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 ListItemIndex) ui_LayoutListButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 ListItemIndex)
{ {
list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex); return ui_Button(Interface, Text);
return ui_LayoutButton(Interface, Layout, Text, Colors.Hover, Colors.Selected, Colors.BGColor);
} }
static b32 static b32
@ -520,10 +693,90 @@ ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, gs_string Text, u
// Punting this till I have a use case // Punting this till I have a use case
InvalidCodePath; InvalidCodePath;
} }
v4 BGColor = ui_GetListItemBGColor(Interface->Style, Index); return ui_Button(Interface, Text, Bounds);
v4 HoverColor = Interface->Style.ListBGHover; }
v4 SelectedColor = Interface->Style.ListBGSelected;
return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); internal bool
ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result EvalResult)
{
ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget.Id);
if (!State) {
State = ui_CreateRetainedState(Interface, Widget.Id);
}
if (EvalResult.Clicked)
{
State->Value = !State->Value;
}
if (State->Value)
{
ui_layout ParentLayout = Interface->LayoutStack[Interface->LayoutStackCount - 1];
r32 SpaceAbove = ParentLayout.Bounds.Max.y - Widget.Bounds.Max.y;
r32 SpaceBelow = Widget.Bounds.Min.y - ParentLayout.Bounds.Min.y;
ui_layout_direction Direction = LayoutDirection_TopDown;
rect2 MenuBounds = {};
if (SpaceAbove > SpaceBelow)
{
r32 ParentLayoutMaxY = ParentLayout.Bounds.Max.y;
Direction = LayoutDirection_BottomUp;
MenuBounds = rect2{
v2{ Widget.Bounds.Min.x, Widget.Bounds.Max.y },
v2{ Widget.Bounds.Max.x, ParentLayoutMaxY }
};
}
else
{
r32 ParentLayoutMinY = ParentLayout.Bounds.Min.y;
Direction = LayoutDirection_TopDown;
MenuBounds = rect2{
v2{ Widget.Bounds.Min.x, ParentLayoutMinY },
v2{ Widget.Bounds.Max.x, Widget.Bounds.Min.y }
};
}
ui_layout Layout = ui_CreateLayout(Interface, MenuBounds, Direction);
Layout.WidgetReference = Widget.Id;
ui_PushLayout(Interface, Layout);
}
return State->Value;
}
internal bool
ui_BeginDropdown(ui_interface* Interface, gs_string Text, rect2 Bounds)
{
ui_widget Widget = ui_CreateWidget(Text);
ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable);
ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground);
ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget, Bounds);
return ui_EvaluateDropdown(Interface, Widget, Result);
}
internal bool
ui_BeginDropdown(ui_interface* Interface, gs_string Text)
{
ui_widget Widget = ui_CreateWidget(Text);
ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable);
ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground);
ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget);
return ui_EvaluateDropdown(Interface, Widget, Result);
}
internal void
ui_EndDropdown(ui_interface* Interface)
{
ui_layout Layout = Interface->LayoutStack[Interface->LayoutStackCount - 1];
ui_widget_retained_state* State = ui_GetRetainedState(Interface, Layout.WidgetReference);
if (State)
{
if (State->Value)
{
ui_PopLayout(Interface);
}
}
} }
// //