began turning ui_layout into ui_widgets that just have children. Currently, layout works, but the id system needs some thinking.
This commit is contained in:
parent
a42d2e81c5
commit
fa1d5a5afc
|
@ -89,35 +89,8 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue)
|
|||
}
|
||||
|
||||
internal void
|
||||
Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer)
|
||||
Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
operation_mode OperationMode = State->Modes.ActiveModes[m];
|
||||
if (OperationMode.Render != 0)
|
||||
{
|
||||
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -169,8 +142,71 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB
|
|||
v4 Color = WhiteV4;
|
||||
PushRenderBoundingBox2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Thickness, Color);
|
||||
}
|
||||
|
||||
if (Widget.ChildrenRoot)
|
||||
{
|
||||
Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot);
|
||||
}
|
||||
|
||||
if (Widget.Next)
|
||||
{
|
||||
Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer)
|
||||
{
|
||||
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
|
||||
PushRenderClearScreen(RenderBuffer);
|
||||
|
||||
ui_InterfaceReset(&State->Interface);
|
||||
State->Interface.RenderBuffer = RenderBuffer;
|
||||
|
||||
ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown);
|
||||
|
||||
rect2 Rects[2];
|
||||
RectVSplitAtPercent(Context->WindowBounds, .5f, &Rects[0], &Rects[1]);
|
||||
for (u32 j = 0; j < 2; j++)
|
||||
{
|
||||
ui_PushLayout(&State->Interface, Rects[j], LayoutDirection_TopDown);
|
||||
|
||||
if (ui_BeginDropdown(&State->Interface, MakeString("Select")))
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_EndDropdown(&State->Interface);
|
||||
|
||||
ui_PopLayout(&State->Interface);
|
||||
}
|
||||
|
||||
#if 0
|
||||
DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context);
|
||||
|
||||
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
|
||||
{
|
||||
operation_mode OperationMode = State->Modes.ActiveModes[m];
|
||||
if (OperationMode.Render != 0)
|
||||
{
|
||||
OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ui_PopLayout(&State->Interface);
|
||||
|
||||
// Draw the Interface
|
||||
ui_widget Widget = *State->Interface.DrawOrderRoot;
|
||||
Editor_DrawWidget(State, Context, RenderBuffer, Widget);
|
||||
|
||||
Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext);
|
||||
Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue);
|
||||
|
||||
|
|
|
@ -240,14 +240,14 @@ SelectAndBeginDragAnimationBlock(animation_timeline_state* TimelineState, handle
|
|||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem);
|
||||
operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip);
|
||||
|
||||
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
|
||||
|
||||
drag_animation_clip_state* OpState = CreateOperationState(DragAnimationClipMode,
|
||||
&State->Modes,
|
||||
drag_animation_clip_state);
|
||||
OpState->TimelineBounds = TimelineBounds;
|
||||
OpState->BlockHandle = BlockHandle;
|
||||
OpState->VisibleRange = VisibleRange;
|
||||
|
||||
animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle);
|
||||
OpState->ClipRange = SelectedBlock->Range;
|
||||
}
|
||||
// -------------------
|
||||
|
@ -303,10 +303,7 @@ DrawFrameBar (animation_system* AnimationSystem, ui_interface Interface, frame_r
|
|||
r32 BarWidth = Rect2Width(BarBounds);
|
||||
|
||||
// Mouse clicked inside frame nubmer bar -> change current frame on timeline
|
||||
// TODO(pjs): both of these functions can get wrapped in a MouseClickedRect
|
||||
// and an alternate MouseIsDraggingRect
|
||||
if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) &&
|
||||
PointIsInRect(BarBounds, Interface.Mouse.DownPos))
|
||||
if (ui_MouseClickedRect(Interface, BarBounds))
|
||||
{
|
||||
StartDragTimeMarker(BarBounds, VisibleFrames, State);
|
||||
}
|
||||
|
@ -590,13 +587,12 @@ 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_PushLayout(Interface, Layout);
|
||||
ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown);
|
||||
for (s32 i = 0; i < GlobalAnimationClipsCount; i++)
|
||||
{
|
||||
animation_clip Clip = GlobalAnimationClips[i];
|
||||
gs_string ClipName = MakeString(Clip.Name, Clip.NameLength);
|
||||
if (ui_LayoutListEntry(Interface, &Layout, ClipName, i))
|
||||
if (ui_LayoutListButton(Interface, ClipName, i))
|
||||
{
|
||||
AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem);
|
||||
}
|
||||
|
@ -609,8 +605,7 @@ 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_PushLayout(Interface, Layout);
|
||||
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown);
|
||||
|
||||
ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]);
|
||||
ui_StartRow(&State->Interface, 4);
|
||||
|
@ -797,8 +792,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende
|
|||
animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem);
|
||||
|
||||
ui_interface* Interface = &State->Interface;
|
||||
ui_layout Layout = ui_CreateLayout(Interface, Bounds);
|
||||
ui_PushLayout(Interface, Layout);
|
||||
ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown);
|
||||
|
||||
ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]);
|
||||
|
||||
|
|
|
@ -88,8 +88,7 @@ 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_PushLayout(&State->Interface, Layout);
|
||||
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown);
|
||||
|
||||
if (ui_Button(&State->Interface, MakeString("Exit")))
|
||||
{
|
||||
|
@ -108,7 +107,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu
|
|||
gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length);
|
||||
gs_string PathString = PushString(State->Transient, FileName.Length);
|
||||
PrintF(&PathString, "%S", FileName);
|
||||
if (ui_LayoutListButton(&State->Interface, &Layout, PathString, i))
|
||||
if (ui_LayoutListButton(&State->Interface, PathString, i))
|
||||
{
|
||||
if (File.IsDirectory)
|
||||
{
|
||||
|
|
|
@ -38,18 +38,21 @@ 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_PushLayout(&State->Interface, Layout);
|
||||
ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown);
|
||||
|
||||
// TODO(pjs): Come back to this after the layout stuff is handled.
|
||||
// Ideally it handles the visuals of the hierarchy itself.
|
||||
|
||||
#if 0
|
||||
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);
|
||||
rect2* LineBounds = PushArray(State->Transient, rect2, LineCount);
|
||||
|
||||
// Fill in alternating color rows for the backgrounds
|
||||
for (u32 Line = 0; Line < LineCount; Line++)
|
||||
{
|
||||
LineBounds[Line] = ui_ReserveElementBounds(&Layout);
|
||||
//LineBounds[Line] = ui_ReserveElementBounds(Layout);
|
||||
v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line);
|
||||
ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor);
|
||||
}
|
||||
|
@ -62,7 +65,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
|
|||
ui_StartRow(&State->Interface, 2);
|
||||
{
|
||||
ui_DrawString(&State->Interface, TempString);
|
||||
if (ui_LayoutListButton(&State->Interface, &Layout, MakeString("X"), AssemblyIndex))
|
||||
if (ui_LayoutListButton(&State->Interface, MakeString("X"), AssemblyIndex))
|
||||
{
|
||||
UnloadAssembly(AssemblyIndex, State, Context);
|
||||
}
|
||||
|
@ -80,6 +83,7 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren
|
|||
Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ui_PopLayout(&State->Interface);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ ProfilerView_Cleanup(panel* Panel, app_state* State)
|
|||
}
|
||||
|
||||
internal void
|
||||
RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
|
||||
RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
|
||||
{
|
||||
v4 ThreadColors[] = {
|
||||
v4{.73f, .33f, .83f, 1},
|
||||
|
@ -35,7 +35,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
|
|||
v4{.74f, .40f, .25f, 1},
|
||||
};
|
||||
|
||||
rect2 Bounds = ui_LayoutRemaining(Layout);
|
||||
rect2 Bounds = ui_LayoutRemaining(*Layout);
|
||||
r32 Width = Rect2Width(Bounds);
|
||||
r32 DepthHeight = 64;
|
||||
|
||||
|
@ -89,7 +89,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb
|
|||
}
|
||||
|
||||
internal void
|
||||
RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
|
||||
RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory)
|
||||
{
|
||||
char Backbuffer[256];
|
||||
gs_string String = MakeString(Backbuffer, 0, 256);
|
||||
|
@ -179,8 +179,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
|
|||
|
||||
debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices);
|
||||
|
||||
ui_layout Layout = ui_CreateLayout(&State->Interface, ProcListBounds);
|
||||
ui_PushLayout(&State->Interface, Layout);
|
||||
ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown);
|
||||
|
||||
ui_StartRow(&State->Interface, 4);
|
||||
{
|
||||
|
@ -195,7 +194,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend
|
|||
|
||||
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
|
||||
// be removed, or used for something else
|
||||
ui_ReserveElementBounds(&Layout);
|
||||
ui_ReserveElementBounds(Layout);
|
||||
|
||||
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
|
||||
{
|
||||
|
|
|
@ -194,14 +194,21 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32
|
|||
enum ui_widget_flag
|
||||
{
|
||||
UIWidgetFlag_DrawBackground,
|
||||
UIWidgetFlag_DrawString,
|
||||
UIWidgetFlag_DrawOutline,
|
||||
UIWidgetFlag_Clickable,
|
||||
};
|
||||
|
||||
struct ui_widget_id
|
||||
{
|
||||
u64 Index;
|
||||
u64 LayoutId;
|
||||
u64 Id;
|
||||
u64 ParentId;
|
||||
};
|
||||
|
||||
enum ui_layout_direction
|
||||
{
|
||||
LayoutDirection_TopDown,
|
||||
LayoutDirection_BottomUp,
|
||||
};
|
||||
|
||||
struct ui_widget
|
||||
|
@ -213,7 +220,31 @@ struct ui_widget
|
|||
|
||||
rect2 Bounds;
|
||||
u64 Flags;
|
||||
bool RetainedState;
|
||||
|
||||
ui_widget* Next;
|
||||
|
||||
// Layout
|
||||
ui_widget* Parent;
|
||||
|
||||
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;
|
||||
|
||||
ui_widget* ChildrenRoot;
|
||||
ui_widget* ChildrenHead;
|
||||
u32 ChildCount;
|
||||
};
|
||||
|
||||
struct ui_eval_result
|
||||
|
@ -241,34 +272,6 @@ 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;
|
||||
|
@ -285,13 +288,13 @@ struct ui_interface
|
|||
u64 WidgetsCount;
|
||||
u64 WidgetsCountMax;
|
||||
|
||||
ui_widget* DrawOrderHead;
|
||||
ui_widget* DrawOrderRoot;
|
||||
|
||||
ui_widget_id HotWidget;
|
||||
ui_widget_id ActiveWidget;
|
||||
|
||||
#define LAYOUT_COUNT_MAX 8
|
||||
ui_layout LayoutStack[LAYOUT_COUNT_MAX];
|
||||
u64 LayoutStackCount;
|
||||
u64 LayoutIdAcc;
|
||||
ui_widget* ActiveLayout;
|
||||
|
||||
#define RETAINED_STATE_MAX 128
|
||||
ui_widget_retained_state RetainedState[RETAINED_STATE_MAX];
|
||||
|
@ -302,14 +305,14 @@ internal void
|
|||
ui_InterfaceReset(ui_interface* Interface)
|
||||
{
|
||||
Interface->WidgetsCount = 0;
|
||||
Interface->LayoutStackCount = 0;
|
||||
Interface->LayoutIdAcc = 0;
|
||||
Interface->DrawOrderHead = 0;
|
||||
Interface->DrawOrderRoot = 0;
|
||||
}
|
||||
|
||||
internal bool
|
||||
ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B)
|
||||
{
|
||||
bool Result = (A.Index == B.Index) && (A.LayoutId == B.LayoutId);
|
||||
bool Result = (A.Id == B.Id) && (A.ParentId == B.ParentId);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
@ -337,6 +340,30 @@ ui_CreateRetainedState(ui_interface* Interface, ui_widget_id Id)
|
|||
return Result;
|
||||
}
|
||||
|
||||
internal ui_widget*
|
||||
ui_CreateWidget(ui_interface* Interface, gs_string String)
|
||||
{
|
||||
Assert(Interface->WidgetsCount < Interface->WidgetsCountMax);
|
||||
ui_widget* Result = Interface->Widgets + Interface->WidgetsCount++;
|
||||
Result->Parent = Interface->ActiveLayout;
|
||||
|
||||
u64 Id = HashDJB2ToU64(StringExpand(String));
|
||||
if (Result->Parent)
|
||||
{
|
||||
Id = HashAppendDJB2ToU32(Id, Result->Parent->Id.Id);
|
||||
Id = HashAppendDJB2ToU32(Id, Result->Parent->ChildCount);
|
||||
}
|
||||
Result->Id.Id = Id;
|
||||
|
||||
Result->String = String;
|
||||
Result->Alignment = Align_Left;
|
||||
Result->Next = 0;
|
||||
Result->ChildrenRoot = 0;
|
||||
Result->ChildrenHead = 0;
|
||||
Result->Flags = 0;
|
||||
return Result;
|
||||
}
|
||||
|
||||
//
|
||||
// Interaction
|
||||
//
|
||||
|
@ -351,94 +378,95 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect)
|
|||
|
||||
// Layout
|
||||
|
||||
static ui_layout
|
||||
ui_CreateLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDirection = LayoutDirection_TopDown)
|
||||
static ui_widget*
|
||||
ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir)
|
||||
{
|
||||
ui_layout Result = {0};
|
||||
Result.Bounds = Bounds;
|
||||
Result.Margin = Interface->Style.Margin;
|
||||
Result.RowHeight = Interface->Style.RowHeight;
|
||||
Result.FillDirection = FillDirection;
|
||||
switch(FillDirection)
|
||||
ui_widget* Result = ui_CreateWidget(Interface, MakeString("Layout"));
|
||||
Result->Bounds = Bounds;
|
||||
Result->Margin = Interface->Style.Margin;
|
||||
Result->RowHeight = Interface->Style.RowHeight;
|
||||
Result->FillDirection = FillDir;
|
||||
switch(FillDir)
|
||||
{
|
||||
case LayoutDirection_BottomUp:
|
||||
{
|
||||
Result.RowYAt = Bounds.Min.y;
|
||||
Result->RowYAt = Bounds.Min.y;
|
||||
}break;
|
||||
|
||||
case LayoutDirection_TopDown:
|
||||
{
|
||||
Result.RowYAt = Bounds.Max.y - Result.RowHeight;
|
||||
Result->RowYAt = Bounds.Max.y - Result->RowHeight;
|
||||
}break;
|
||||
}
|
||||
|
||||
Result.Id = ++Interface->LayoutIdAcc;
|
||||
|
||||
if (Interface->DrawOrderRoot)
|
||||
{
|
||||
SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Result);
|
||||
Interface->ActiveLayout->ChildCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result);
|
||||
}
|
||||
Interface->ActiveLayout = Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
static void
|
||||
ui_PushLayout(ui_interface* Interface, ui_layout Layout)
|
||||
{
|
||||
Assert(Interface->LayoutStackCount < LAYOUT_COUNT_MAX);
|
||||
Interface->LayoutStack[Interface->LayoutStackCount++] = Layout;
|
||||
}
|
||||
internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds);
|
||||
|
||||
static void
|
||||
ui_PopLayout(ui_interface* Interface)
|
||||
{
|
||||
Assert(Interface->LayoutStackCount > 0);
|
||||
Interface->LayoutStackCount -= 1;
|
||||
Assert(Interface->ActiveLayout != 0);
|
||||
ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds);
|
||||
Interface->ActiveLayout = Interface->ActiveLayout->Parent;
|
||||
}
|
||||
|
||||
static void
|
||||
ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 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;
|
||||
Interface->ActiveLayout->DrawHorizontal = true;
|
||||
Interface->ActiveLayout->ColumnsMax = ColumnsMax;
|
||||
Interface->ActiveLayout->ColumnWidths = 0;
|
||||
Interface->ActiveLayout->ColumnsCount = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths)
|
||||
{
|
||||
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;
|
||||
Interface->ActiveLayout->DrawHorizontal = true;
|
||||
Interface->ActiveLayout->ColumnsMax = ColumnsMax;
|
||||
Interface->ActiveLayout->ColumnWidths = ColumnWidths;
|
||||
Interface->ActiveLayout->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;
|
||||
Interface->ActiveLayout->DrawHorizontal = false;
|
||||
Interface->ActiveLayout->ColumnWidths = 0;
|
||||
Interface->ActiveLayout->RowYAt -= Interface->ActiveLayout->RowHeight;
|
||||
}
|
||||
|
||||
static b32
|
||||
ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
|
||||
ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds)
|
||||
{
|
||||
b32 Result = true;
|
||||
if (!Layout->DrawHorizontal)
|
||||
if (!Widget->DrawHorizontal)
|
||||
{
|
||||
Bounds->Min = { Layout->Bounds.Min.x, Layout->RowYAt };
|
||||
Bounds->Max = { Layout->Bounds.Max.x, Bounds->Min.y + Layout->RowHeight };
|
||||
Bounds->Min = { Widget->Bounds.Min.x, Widget->RowYAt };
|
||||
Bounds->Max = { Widget->Bounds.Max.x, Bounds->Min.y + Widget->RowHeight };
|
||||
|
||||
switch (Layout->FillDirection)
|
||||
switch (Widget->FillDirection)
|
||||
{
|
||||
case LayoutDirection_BottomUp:
|
||||
{
|
||||
Layout->RowYAt += Layout->RowHeight;
|
||||
Widget->RowYAt += Widget->RowHeight;
|
||||
}break;
|
||||
|
||||
case LayoutDirection_TopDown:
|
||||
{
|
||||
Layout->RowYAt -= Layout->RowHeight;
|
||||
Widget->RowYAt -= Widget->RowHeight;
|
||||
}break;
|
||||
|
||||
InvalidDefaultCase;
|
||||
|
@ -446,32 +474,32 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (Layout->ColumnsMax > 0)
|
||||
if (Widget->ColumnsMax > 0)
|
||||
{
|
||||
Assert(Layout->ColumnsCount < Layout->ColumnsMax);
|
||||
if (Layout->ColumnWidths != 0)
|
||||
Assert(Widget->ColumnsCount < Widget->ColumnsMax);
|
||||
if (Widget->ColumnWidths != 0)
|
||||
{
|
||||
v2 Min = { Layout->Bounds.Min.x, Layout->RowYAt };
|
||||
for (u32 i = 0; i < Layout->ColumnsCount; i++)
|
||||
v2 Min = { Widget->Bounds.Min.x, Widget->RowYAt };
|
||||
for (u32 i = 0; i < Widget->ColumnsCount; i++)
|
||||
{
|
||||
Min.x += Layout->ColumnWidths[i];
|
||||
Min.x += Widget->ColumnWidths[i];
|
||||
}
|
||||
Bounds->Min = Min;
|
||||
Bounds->Max = Bounds->Min + v2{ Layout->ColumnWidths[Layout->ColumnsCount], Layout->RowHeight };
|
||||
Bounds->Max = Bounds->Min + v2{ Widget->ColumnWidths[Widget->ColumnsCount], Widget->RowHeight };
|
||||
}
|
||||
else
|
||||
{
|
||||
r32 ElementWidth = Rect2Width(Layout->Bounds) / Layout->ColumnsMax;
|
||||
r32 ElementWidth = Rect2Width(Widget->Bounds) / Widget->ColumnsMax;
|
||||
Bounds->Min = {
|
||||
Layout->Bounds.Min.x + (ElementWidth * Layout->ColumnsCount) + Layout->Margin.x,
|
||||
Layout->RowYAt
|
||||
Widget->Bounds.Min.x + (ElementWidth * Widget->ColumnsCount) + Widget->Margin.x,
|
||||
Widget->RowYAt
|
||||
};
|
||||
Bounds->Max = {
|
||||
Bounds->Min.x + ElementWidth - Layout->Margin.x,
|
||||
Bounds->Min.y + Layout->RowHeight
|
||||
Bounds->Min.x + ElementWidth - Widget->Margin.x,
|
||||
Bounds->Min.y + Widget->RowHeight
|
||||
};
|
||||
}
|
||||
Layout->ColumnsCount++;
|
||||
Widget->ColumnsCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -482,7 +510,7 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds)
|
|||
}
|
||||
|
||||
static rect2
|
||||
ui_ReserveElementBounds(ui_layout* Layout)
|
||||
ui_ReserveElementBounds(ui_widget* Layout)
|
||||
{
|
||||
rect2 Bounds = {0};
|
||||
if (!ui_TryReserveElementBounds(Layout, &Bounds))
|
||||
|
@ -493,7 +521,7 @@ ui_ReserveElementBounds(ui_layout* Layout)
|
|||
}
|
||||
|
||||
static rect2
|
||||
ui_LayoutRemaining(ui_layout Layout)
|
||||
ui_LayoutRemaining(ui_widget Layout)
|
||||
{
|
||||
rect2 Result = Layout.Bounds;
|
||||
Result.Max.y = Layout.RowYAt;
|
||||
|
@ -506,15 +534,6 @@ ui_LayoutRemaining(ui_layout Layout)
|
|||
|
||||
// Widgets
|
||||
|
||||
internal ui_widget
|
||||
ui_CreateWidget(gs_string String)
|
||||
{
|
||||
ui_widget Result = {};
|
||||
Result.String = String;
|
||||
Result.Alignment = Align_Left;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
ui_WidgetSetFlag(ui_widget* Widget, u64 Flag)
|
||||
{
|
||||
|
@ -535,12 +554,15 @@ 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;
|
||||
//Assert(Interface->WidgetsCount < Interface->WidgetsCountMax);
|
||||
//u64 Index = Interface->WidgetsCount++;
|
||||
|
||||
Widget->Id.Id = HashDJB2ToU64(StringExpand(Widget->String));
|
||||
Widget->Id.ParentId = Interface->ActiveLayout->Id.Id;
|
||||
|
||||
Widget->Bounds = Bounds;
|
||||
Interface->Widgets[Widget->Id.Index] = *Widget;
|
||||
//Interface->Widgets[Index] = *Widget;
|
||||
SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget);
|
||||
|
||||
if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable))
|
||||
{
|
||||
|
@ -569,7 +591,7 @@ internal ui_eval_result
|
|||
ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget)
|
||||
{
|
||||
rect2 Bounds = {0};
|
||||
ui_layout* Layout = Interface->LayoutStack + Interface->LayoutStackCount - 1;
|
||||
ui_widget* Layout = Interface->ActiveLayout;
|
||||
if (!ui_TryReserveElementBounds(Layout, &Bounds))
|
||||
{
|
||||
// TODO(pjs): This isn't invalid, but Idk when we'd hit this case yet
|
||||
|
@ -606,36 +628,38 @@ internal void
|
|||
ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
ui_widget Widget = ui_CreateWidget(String);
|
||||
Widget.Bounds = Bounds;
|
||||
ui_EvaluateWidget(Interface, &Widget);
|
||||
ui_widget* Widget = ui_CreateWidget(Interface, String);
|
||||
Widget->Bounds = Bounds;
|
||||
ui_EvaluateWidget(Interface, Widget);
|
||||
}
|
||||
|
||||
internal void
|
||||
ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
ui_widget Widget = ui_CreateWidget(String);
|
||||
ui_EvaluateWidget(Interface, &Widget);
|
||||
ui_widget* Widget = ui_CreateWidget(Interface, String);
|
||||
ui_EvaluateWidget(Interface, Widget);
|
||||
}
|
||||
|
||||
static b32
|
||||
ui_Button(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);
|
||||
ui_widget* Widget = ui_CreateWidget(Interface, Text);
|
||||
ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable);
|
||||
ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground);
|
||||
ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString);
|
||||
ui_eval_result Result = ui_EvaluateWidget(Interface, Widget);
|
||||
return Result.Clicked;
|
||||
}
|
||||
|
||||
static b32
|
||||
ui_Button(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);
|
||||
ui_widget* Widget = ui_CreateWidget(Interface, Text);
|
||||
ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable);
|
||||
ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground);
|
||||
ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString);
|
||||
ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds);
|
||||
return Result.Clicked;
|
||||
}
|
||||
|
||||
|
@ -666,42 +690,28 @@ ui_GetListItemColors(ui_interface* Interface, u32 ListItemIndex)
|
|||
static b32
|
||||
ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex)
|
||||
{
|
||||
ui_widget Widget = ui_CreateWidget(Text);
|
||||
ui_WidgetSetFlag(&Widget, UIWidgetFlag_DrawBackground);
|
||||
ui_WidgetSetFlag(&Widget, UIWidgetFlag_Clickable);
|
||||
ui_widget* Widget = ui_CreateWidget(Interface, 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);
|
||||
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)
|
||||
ui_LayoutListButton(ui_interface* Interface, gs_string Text, u32 ListItemIndex)
|
||||
{
|
||||
// TODO(pjs): Reimplement alternating colors
|
||||
return ui_Button(Interface, Text);
|
||||
}
|
||||
|
||||
static b32
|
||||
ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 Index)
|
||||
{
|
||||
rect2 Bounds = {0};
|
||||
if (!ui_TryReserveElementBounds(Layout, &Bounds))
|
||||
{
|
||||
// TODO(Peter): this isn't really invalid, but I don't have a concrete use case
|
||||
// for it yet. This should only fire if the Layout component is drawing a row,
|
||||
// but if you're in row mode during a list, what should happen?
|
||||
// Punting this till I have a use case
|
||||
InvalidCodePath;
|
||||
}
|
||||
return ui_Button(Interface, Text, Bounds);
|
||||
}
|
||||
|
||||
internal bool
|
||||
ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result EvalResult)
|
||||
ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result EvalResult)
|
||||
{
|
||||
ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget.Id);
|
||||
ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id);
|
||||
if (!State) {
|
||||
State = ui_CreateRetainedState(Interface, Widget.Id);
|
||||
State = ui_CreateRetainedState(Interface, Widget->Id);
|
||||
}
|
||||
|
||||
if (EvalResult.Clicked)
|
||||
|
@ -711,10 +721,10 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev
|
|||
|
||||
if (State->Value)
|
||||
{
|
||||
ui_layout ParentLayout = Interface->LayoutStack[Interface->LayoutStackCount - 1];
|
||||
ui_widget ParentLayout = *Interface->ActiveLayout;
|
||||
|
||||
r32 SpaceAbove = ParentLayout.Bounds.Max.y - Widget.Bounds.Max.y;
|
||||
r32 SpaceBelow = Widget.Bounds.Min.y - ParentLayout.Bounds.Min.y;
|
||||
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 = {};
|
||||
|
||||
|
@ -723,8 +733,8 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev
|
|||
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 }
|
||||
v2{ Widget->Bounds.Min.x, Widget->Bounds.Max.y },
|
||||
v2{ Widget->Bounds.Max.x, ParentLayoutMaxY }
|
||||
};
|
||||
}
|
||||
else
|
||||
|
@ -732,14 +742,13 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev
|
|||
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 }
|
||||
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);
|
||||
ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction);
|
||||
Layout->WidgetReference = Widget->Id;
|
||||
}
|
||||
|
||||
return State->Value;
|
||||
|
@ -748,28 +757,28 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget Widget, ui_eval_result Ev
|
|||
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);
|
||||
ui_widget* Widget = ui_CreateWidget(Interface, 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);
|
||||
ui_widget* Widget = ui_CreateWidget(Interface, 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);
|
||||
ui_widget* Layout = Interface->ActiveLayout;
|
||||
ui_widget_retained_state* State = ui_GetRetainedState(Interface, Layout->WidgetReference);
|
||||
if (State)
|
||||
{
|
||||
if (State->Value)
|
||||
|
|
|
@ -3111,6 +3111,24 @@ TimeHandlerGetSecondsElapsed(gs_time_handler TimeHandler, s64 StartCycles, s64 E
|
|||
//
|
||||
// Hashes
|
||||
|
||||
internal u32
|
||||
HashAppendDJB2ToU32(u32 Hash, u8 Byte)
|
||||
{
|
||||
u32 Result = Hash;
|
||||
if (Result == 0) { Result = 5381; }
|
||||
Result = ((Result << 5) + Result) + Byte;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal u64
|
||||
HashAppendDJB2ToU32(u64 Hash, u8 Byte)
|
||||
{
|
||||
u64 Result = Hash;
|
||||
if (Result == 0) { Result = 5381; }
|
||||
Result = ((Result << 5) + Result) + Byte;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal u32
|
||||
HashDJB2ToU32(char* String)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue