Pretty big ui overhaul.
This commit is contained in:
parent
723458c491
commit
d5be2a2de8
|
@ -84,8 +84,12 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB
|
|||
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
|
||||
PushRenderClearScreen(RenderBuffer);
|
||||
|
||||
ui_InterfaceReset(&State->Interface);
|
||||
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);
|
||||
|
||||
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->ResetWorkQueue(Context->GeneralWorkQueue);
|
||||
|
||||
|
|
|
@ -388,42 +388,19 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB
|
|||
|
||||
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++)
|
||||
{
|
||||
panel_definition Def = State->PanelSystem.PanelDefs[i];
|
||||
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->PanelSelectionMenuOpen = false;
|
||||
}
|
||||
|
||||
ButtonBounds = Rect2TranslateY(ButtonBounds, Rect2Height(ButtonBounds));
|
||||
}
|
||||
}
|
||||
|
||||
if (ui_Button(&State->Interface, MakeString("Select"), PanelSelectBtnBounds))
|
||||
{
|
||||
Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen;
|
||||
}
|
||||
|
||||
ui_EndDropdown(&State->Interface);
|
||||
}
|
||||
|
||||
internal void
|
||||
|
|
|
@ -36,10 +36,6 @@ struct panel
|
|||
panel_split_direction SplitDirection;
|
||||
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;
|
||||
|
||||
union{
|
||||
|
|
|
@ -588,7 +588,8 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback)
|
|||
internal void
|
||||
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++)
|
||||
{
|
||||
animation_clip Clip = GlobalAnimationClips[i];
|
||||
|
@ -598,6 +599,7 @@ DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedA
|
|||
AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem);
|
||||
}
|
||||
}
|
||||
ui_PopLayout(Interface);
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -605,34 +607,36 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan
|
|||
{
|
||||
animation_system* AnimSystem = &State->AnimationSystem;
|
||||
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_StartRow(&Layout, 4);
|
||||
ui_StartRow(&State->Interface, 4);
|
||||
{
|
||||
if (ui_LayoutButton(Interface, &Layout, MakeString("Pause")))
|
||||
if (ui_Button(Interface, MakeString("Pause")))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (ui_LayoutButton(Interface, &Layout, MakeString("Stop")))
|
||||
if (ui_Button(Interface, MakeString("Stop")))
|
||||
{
|
||||
AnimSystem->TimelineShouldAdvance = false;
|
||||
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_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback);
|
||||
}
|
||||
}
|
||||
ui_EndRow(&Layout);
|
||||
ui_EndRow(&State->Interface);
|
||||
ui_PopLayout(&State->Interface);
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -787,7 +791,33 @@ TimeRange_Render(animation_timeline_state* TimelineState, rect2 Bounds, render_c
|
|||
internal void
|
||||
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
|
||||
|
@ -807,7 +837,7 @@ AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer*
|
|||
RectVSplit(PanelBounds, 300, &InfoBounds, &TimelineBounds);
|
||||
|
||||
rect2 AnimInfoBounds, SelectionInfoBounds;
|
||||
RectHSplitAtPercent(InfoBounds, .35f, &AnimInfoBounds, &SelectionInfoBounds);
|
||||
RectHSplitAtPercent(InfoBounds, .65f, &AnimInfoBounds, &SelectionInfoBounds);
|
||||
|
||||
{ // Timeline
|
||||
rect2 LayersPanelBounds, TimeRangePanelBounds;
|
||||
|
|
|
@ -88,15 +88,16 @@ internal void
|
|||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
// Header
|
||||
ui_LayoutDrawString(&State->Interface, &Layout, FileViewState->WorkingDirectory, v4{0, 1, 0, 1});
|
||||
ui_DrawString(&State->Interface, FileViewState->WorkingDirectory);
|
||||
|
||||
// File Display
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,9 @@ GSMetaTag(panel_type_hierarchy);
|
|||
internal void
|
||||
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);
|
||||
u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1;
|
||||
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];
|
||||
PrintF(&TempString, "%S", Assembly.Name);
|
||||
|
||||
ui_layout ItemLayout = ui_CreateLayout(State->Interface, LineBounds[AssemblyIndex]);
|
||||
ui_StartRow(&ItemLayout, 2);
|
||||
ui_StartRow(&State->Interface, 2);
|
||||
{
|
||||
ui_LayoutDrawString(&State->Interface, &ItemLayout, TempString, State->Interface.Style.TextColor);
|
||||
if (ui_LayoutListButton(&State->Interface, &ItemLayout, MakeString("X"), AssemblyIndex))
|
||||
ui_DrawString(&State->Interface, TempString);
|
||||
if (ui_LayoutListButton(&State->Interface, &Layout, MakeString("X"), AssemblyIndex))
|
||||
{
|
||||
UnloadAssembly(AssemblyIndex, State, Context);
|
||||
}
|
||||
}
|
||||
ui_EndRow(&ItemLayout);
|
||||
ui_EndRow(&State->Interface);
|
||||
}
|
||||
|
||||
if (AssembliesToDraw < LineCount)
|
||||
|
@ -79,6 +80,8 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
|
|||
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
|
||||
}
|
||||
}
|
||||
|
||||
ui_PopLayout(&State->Interface);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
|
|||
PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles);
|
||||
|
||||
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);
|
||||
|
||||
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_LayoutDrawString(Interface, &Layout, MakeString("% Frame"), Interface->Style.TextColor);
|
||||
ui_LayoutDrawString(Interface, &Layout, MakeString("Seconds"), Interface->Style.TextColor);
|
||||
ui_LayoutDrawString(Interface, &Layout, MakeString("Cycles"), Interface->Style.TextColor);
|
||||
ui_LayoutDrawString(Interface, &Layout, MakeString("Calls"), Interface->Style.TextColor);
|
||||
ui_DrawString(Interface, MakeString("Procedure"));
|
||||
ui_DrawString(Interface, MakeString("% Frame"));
|
||||
ui_DrawString(Interface, MakeString("Seconds"));
|
||||
ui_DrawString(Interface, MakeString("Cycles"));
|
||||
ui_DrawString(Interface, MakeString("Calls"));
|
||||
}
|
||||
ui_EndRow(&Layout);
|
||||
ui_EndRow(Interface);
|
||||
|
||||
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;
|
||||
|
||||
ui_StartRow(&Layout, 5, &ColumnWidths[0]);
|
||||
ui_StartRow(Interface, 5, &ColumnWidths[0]);
|
||||
{
|
||||
PrintF(&String, "%S", NameEntry.Name);
|
||||
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor);
|
||||
ui_DrawString(Interface, String);
|
||||
|
||||
PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime);
|
||||
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor);
|
||||
ui_DrawString(Interface, String);
|
||||
|
||||
PrintF(&String, "%fs", CollatedRecord->TotalSeconds);
|
||||
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor);
|
||||
ui_DrawString(Interface, String);
|
||||
|
||||
PrintF(&String, "%dcy", CollatedRecord->TotalCycles);
|
||||
ui_LayoutDrawString(Interface, &Layout, String, Interface->Style.TextColor);
|
||||
ui_DrawString(Interface, String);
|
||||
|
||||
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);
|
||||
|
||||
ui_layout Layout = ui_CreateLayout(State->Interface, ProcListBounds);
|
||||
ui_StartRow(&Layout, 4);
|
||||
ui_layout Layout = ui_CreateLayout(&State->Interface, ProcListBounds);
|
||||
ui_PushLayout(&State->Interface, Layout);
|
||||
|
||||
ui_StartRow(&State->Interface, 4);
|
||||
{
|
||||
s64 FrameStartCycles = VisibleFrame->FrameStartCycles;
|
||||
s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles;
|
||||
u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1;
|
||||
PrintF(&String, "Frame %d", CurrentDebugFrame);
|
||||
ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4);
|
||||
ui_DrawString(&State->Interface, String);
|
||||
|
||||
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
|
||||
// be removed, or used for something else
|
||||
ui_ReserveElementBounds(&Layout);
|
||||
|
||||
if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Resume Recording")))
|
||||
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (ui_LayoutButton(&State->Interface, &Layout, MakeString("List View")))
|
||||
if (ui_Button(&State->Interface, MakeString("List View")))
|
||||
{
|
||||
GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST;
|
||||
}
|
||||
}
|
||||
ui_EndRow(&Layout);
|
||||
ui_EndRow(&State->Interface);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ui_PopLayout(&State->Interface);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
|||
State->Interface.Style.PanelBGColors[3] = v4{.6f, .6f, .6f, 1};
|
||||
State->Interface.Style.ButtonColor_Inactive = BlackV4;
|
||||
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.ListBGColors[0] = v4{ .16f, .16f, .16f, 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.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->Camera.FieldOfView = 45.0f;
|
||||
|
@ -119,8 +122,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
|||
State->Camera.Near = .1f;
|
||||
State->Camera.Far = 800.0f;
|
||||
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);
|
||||
|
||||
|
|
|
@ -5,6 +5,14 @@
|
|||
//
|
||||
#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
|
||||
{
|
||||
Align_Left,
|
||||
|
@ -129,7 +137,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col
|
|||
}
|
||||
|
||||
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;
|
||||
v2 LowerRight = Position;
|
||||
|
@ -180,10 +188,44 @@ Drawgs_stringWithCursor (render_command_buffer* RenderBuffer, gs_string String,
|
|||
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
|
||||
{
|
||||
v4 PanelBGColors[4];
|
||||
|
||||
// TODO(pjs): Turn these into _Default, _Hot, _Active
|
||||
v4 ButtonColor_Inactive, ButtonColor_Active, ButtonColor_Selected;
|
||||
|
||||
v4 TextColor;
|
||||
|
@ -199,17 +241,38 @@ struct interface_config
|
|||
r32 RowHeight;
|
||||
};
|
||||
|
||||
enum ui_layout_direction
|
||||
{
|
||||
LayoutDirection_TopDown,
|
||||
LayoutDirection_BottomUp,
|
||||
};
|
||||
|
||||
struct ui_layout
|
||||
{
|
||||
u64 Id;
|
||||
|
||||
rect2 Bounds;
|
||||
v2 Margin;
|
||||
r32 RowHeight;
|
||||
r32 RowYAt;
|
||||
|
||||
ui_layout_direction FillDirection;
|
||||
|
||||
b32 DrawHorizontal;
|
||||
u32 ColumnsMax;
|
||||
r32* ColumnWidths;
|
||||
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
|
||||
|
@ -217,49 +280,144 @@ struct ui_interface
|
|||
interface_config Style;
|
||||
mouse_state Mouse;
|
||||
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
|
||||
ui_CreateLayout(ui_interface Interface, rect2 Bounds)
|
||||
ui_CreateLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDirection = LayoutDirection_TopDown)
|
||||
{
|
||||
ui_layout Result = {0};
|
||||
Result.Bounds = Bounds;
|
||||
Result.Margin = Interface.Style.Margin;
|
||||
Result.RowHeight = Interface.Style.RowHeight;
|
||||
Result.RowYAt = Bounds.Max.y - Result.RowHeight;
|
||||
Result.Margin = Interface->Style.Margin;
|
||||
Result.RowHeight = Interface->Style.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;
|
||||
}
|
||||
|
||||
static void
|
||||
ui_StartRow(ui_layout* Layout, u32 ColumnsMax)
|
||||
ui_PushLayout(ui_interface* Interface, ui_layout Layout)
|
||||
{
|
||||
Layout->DrawHorizontal = true;
|
||||
Layout->ColumnsMax = ColumnsMax;
|
||||
Layout->ColumnWidths = 0;
|
||||
Layout->ColumnsCount = 0;
|
||||
Assert(Interface->LayoutStackCount < LAYOUT_COUNT_MAX);
|
||||
Interface->LayoutStack[Interface->LayoutStackCount++] = Layout;
|
||||
}
|
||||
|
||||
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
|
||||
ui_StartRow(ui_layout* Layout, u32 ColumnsMax, r32* ColumnWidths)
|
||||
ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 0)
|
||||
{
|
||||
Layout->DrawHorizontal = true;
|
||||
Layout->ColumnsMax = ColumnsMax;
|
||||
Layout->ColumnWidths = ColumnWidths;
|
||||
Layout->ColumnsCount = 0;
|
||||
u64 LayoutIdx = Interface->LayoutStackCount - 1;
|
||||
Interface->LayoutStack[LayoutIdx].DrawHorizontal = true;
|
||||
Interface->LayoutStack[LayoutIdx].ColumnsMax = ColumnsMax;
|
||||
Interface->LayoutStack[LayoutIdx].ColumnWidths = 0;
|
||||
Interface->LayoutStack[LayoutIdx].ColumnsCount = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ui_EndRow(ui_layout* Layout)
|
||||
ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths)
|
||||
{
|
||||
Layout->DrawHorizontal = false;
|
||||
Layout->ColumnWidths = 0;
|
||||
Layout->RowYAt -= Layout->RowHeight;
|
||||
u64 LayoutIdx = Interface->LayoutStackCount - 1;
|
||||
Interface->LayoutStack[LayoutIdx].DrawHorizontal = true;
|
||||
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
|
||||
|
@ -270,7 +428,21 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
|
|||
{
|
||||
Bounds->Min = { Layout->Bounds.Min.x, Layout->RowYAt };
|
||||
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
|
||||
{
|
||||
|
@ -309,14 +481,6 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
|
|||
return Result;
|
||||
}
|
||||
|
||||
static rect2
|
||||
ui_ReserveTextLineBounds(ui_interface Interface, gs_string Text, ui_layout* Layout)
|
||||
{
|
||||
rect2 Bounds = {0};
|
||||
|
||||
return Bounds;
|
||||
}
|
||||
|
||||
static rect2
|
||||
ui_ReserveElementBounds(ui_layout* Layout)
|
||||
{
|
||||
|
@ -340,18 +504,81 @@ ui_LayoutRemaining(ui_layout Layout)
|
|||
return Result;
|
||||
}
|
||||
|
||||
//
|
||||
// Interaction
|
||||
//
|
||||
// Widgets
|
||||
|
||||
internal b32
|
||||
ui_MouseClickedRect(ui_interface Interface, rect2 Rect)
|
||||
internal ui_widget
|
||||
ui_CreateWidget(gs_string String)
|
||||
{
|
||||
b32 Result = MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState);
|
||||
Result &= PointIsInRect(Rect, Interface.Mouse.Pos);
|
||||
ui_widget Result = {};
|
||||
Result.String = String;
|
||||
Result.Alignment = Align_Left;
|
||||
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
|
||||
//
|
||||
|
@ -376,78 +603,40 @@ ui_OutlineRect(ui_interface* Interface, rect2 Bounds, r32 Thickness, v4 Color)
|
|||
}
|
||||
|
||||
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;
|
||||
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(Interface->RenderBuffer,
|
||||
String.Length,
|
||||
Interface->Style.Font->BitmapMemory,
|
||||
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;
|
||||
}
|
||||
ui_widget Widget = ui_CreateWidget(String);
|
||||
Widget.Bounds = Bounds;
|
||||
ui_EvaluateWidget(Interface, &Widget);
|
||||
}
|
||||
|
||||
static void
|
||||
ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, gs_string String, v4 Color, gs_string_alignment Alignment = Align_Left)
|
||||
internal void
|
||||
ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left)
|
||||
{
|
||||
rect2 Bounds = {0};
|
||||
if (!ui_TryReserveElementBounds(Layout, &Bounds))
|
||||
{
|
||||
// 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);
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
ui_widget Widget = ui_CreateWidget(String);
|
||||
ui_EvaluateWidget(Interface, &Widget);
|
||||
}
|
||||
|
||||
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;
|
||||
v4 ButtonBG = InactiveColor;
|
||||
if (PointIsInRect(Bounds, Interface->Mouse.Pos))
|
||||
{
|
||||
ButtonBG = HoverColor;
|
||||
if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState))
|
||||
{
|
||||
ButtonBG = ClickedColor;
|
||||
Pressed = true;
|
||||
}
|
||||
}
|
||||
ui_TextBox(Interface, Bounds, Text, ButtonBG, Interface->Style.TextColor);
|
||||
return Pressed;
|
||||
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 Result.Clicked;
|
||||
}
|
||||
|
||||
static b32
|
||||
ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds)
|
||||
{
|
||||
v4 BGColor = Interface->Style.ButtonColor_Inactive;
|
||||
v4 HoverColor = Interface->Style.ButtonColor_Active;
|
||||
v4 SelectedColor = Interface->Style.ButtonColor_Selected;
|
||||
return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor);
|
||||
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 Result.Clicked;
|
||||
}
|
||||
|
||||
struct list_item_colors
|
||||
|
@ -477,35 +666,19 @@ ui_GetListItemColors(ui_interface* Interface, u32 ListItemIndex)
|
|||
static b32
|
||||
ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex)
|
||||
{
|
||||
list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex);
|
||||
return ui_Button(Interface, Text, Bounds, Colors.Hover, Colors.Selected, Colors.BGColor);
|
||||
}
|
||||
|
||||
static b32
|
||||
ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, v4 BGColor, v4 HoverColor, v4 SelectColor)
|
||||
{
|
||||
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);
|
||||
ui_widget Widget = ui_CreateWidget(Text);
|
||||
ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground);
|
||||
ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable);
|
||||
// TODO(pjs): Reimplement alternating color backgrounds
|
||||
Widget.Bounds = Bounds;
|
||||
ui_eval_result Result = ui_EvaluateWidget(Interface, &Widget);
|
||||
return Result.Clicked;
|
||||
}
|
||||
|
||||
static b32
|
||||
ui_LayoutListButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 ListItemIndex)
|
||||
{
|
||||
list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex);
|
||||
return ui_LayoutButton(Interface, Layout, Text, Colors.Hover, Colors.Selected, Colors.BGColor);
|
||||
return ui_Button(Interface, Text);
|
||||
}
|
||||
|
||||
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
|
||||
InvalidCodePath;
|
||||
}
|
||||
v4 BGColor = ui_GetListItemBGColor(Interface->Style, Index);
|
||||
v4 HoverColor = Interface->Style.ListBGHover;
|
||||
v4 SelectedColor = Interface->Style.ListBGSelected;
|
||||
return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor);
|
||||
return ui_Button(Interface, Text, Bounds);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue