diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 5d08c1f..ecef055 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -88,6 +88,72 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } +internal void +Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) +{ + 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); + } + + 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) { @@ -97,9 +163,32 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; - ui_layout Layout = ui_CreateLayout(&State->Interface, Context->WindowBounds); - ui_PushLayout(&State->Interface, Layout); + 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++) @@ -110,66 +199,13 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); } } +#endif 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); - } - } + ui_widget Widget = *State->Interface.DrawOrderRoot; + Editor_DrawWidget(State, Context, RenderBuffer, Widget); Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 6210cfa..1bd2d16 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -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]); diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index f4427c0..b80ba25 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -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) { diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index 54b6b8c..d110e17 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -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); } diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 0f38547..7cdf042 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -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"))) { diff --git a/src/app/interface.h b/src/app/interface.h index d390069..6509468 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -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) diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index 05467cc..a42bdae 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -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) {