From fa1d5a5afca53a7c7a454637547e2a08b79c108f Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 8 Nov 2020 19:42:14 -0800 Subject: [PATCH 01/10] began turning ui_layout into ui_widgets that just have children. Currently, layout works, but the id system needs some thinking. --- src/app/editor/foldhaus_editor.cpp | 152 +++++--- .../foldhaus_panel_animation_timeline.h | 20 +- .../editor/panels/foldhaus_panel_file_view.h | 5 +- .../editor/panels/foldhaus_panel_hierarchy.h | 14 +- .../editor/panels/foldhaus_panel_profiler.h | 11 +- src/app/interface.h | 339 +++++++++--------- src/gs_libs/gs_types.cpp | 18 + 7 files changed, 309 insertions(+), 250 deletions(-) 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) { From 30123e47a2fb371c32a2a3926175457a32a1a91b Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 17:18:38 -0800 Subject: [PATCH 02/10] fixed some problems with ui retained states --- src/app/editor/foldhaus_editor.cpp | 53 ++++++++----- src/app/editor/foldhaus_interface.cpp | 3 +- .../foldhaus_panel_animation_timeline.h | 6 +- .../editor/panels/foldhaus_panel_file_view.h | 2 +- .../editor/panels/foldhaus_panel_hierarchy.h | 2 +- .../editor/panels/foldhaus_panel_profiler.h | 2 +- src/app/foldhaus_app.cpp | 3 +- src/app/interface.h | 76 +++++++++++-------- src/app/platform_win32/win32_foldhaus.cpp | 6 +- .../win32_foldhaus_work_queue.h | 2 + src/gs_libs/gs_types.cpp | 25 ++++-- src/todo.txt | 1 - src/todo_done.txt | 2 + 13 files changed, 120 insertions(+), 63 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index ecef055..cd3e5f5 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -105,7 +105,7 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren PushRenderQuad2D(RenderBuffer, Widget.Bounds.Min, Widget.Bounds.Max, Color); } - if (Widget.String.Length > 0) + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) { v4 Color = State->Interface.Style.TextColor; render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer, @@ -155,25 +155,22 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren } internal void -Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) +TestRender(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); + ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("TestRender Layout")); - rect2 Rects[2]; - RectVSplitAtPercent(Context->WindowBounds, .5f, &Rects[0], &Rects[1]); + ui_widget_id Ids[2]; + + gs_string String = MakeString("Select"); + ui_StartRow(&State->Interface, 2); for (u32 j = 0; j < 2; j++) { - ui_PushLayout(&State->Interface, Rects[j], LayoutDirection_TopDown); - - if (ui_BeginDropdown(&State->Interface, MakeString("Select"))) + if (ui_BeginDropdown(&State->Interface, String)) { - for (s32 i = 0; i < GlobalPanelDefsCount; i++) + for (u32 i = 0; i < State->PanelSystem.PanelDefsCount; i++) { panel_definition Def = State->PanelSystem.PanelDefs[i]; gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); @@ -184,11 +181,30 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB } } ui_EndDropdown(&State->Interface); - - ui_PopLayout(&State->Interface); } + ui_EndRow(&State->Interface); + + ui_PopLayout(&State->Interface); + + Assert(!ui_WidgetIdsEqual(Ids[0], Ids[1])); +} + +internal void +Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) +{ + PushRenderOrthographic(RenderBuffer, State->WindowBounds); + PushRenderClearScreen(RenderBuffer); #if 0 + TestRender(State, Context, RenderBuffer); + //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); + //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); + +#else + ui_InterfaceReset(&State->Interface); + State->Interface.RenderBuffer = RenderBuffer; + ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout")); + DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) @@ -199,13 +215,16 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); } } -#endif ui_PopLayout(&State->Interface); +#endif // Draw the Interface - ui_widget Widget = *State->Interface.DrawOrderRoot; - Editor_DrawWidget(State, Context, RenderBuffer, Widget); + if (State->Interface.DrawOrderRoot != 0) + { + 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/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp index 7a83912..29258ec 100644 --- a/src/app/editor/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -386,7 +386,8 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterB rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23}); - if (ui_BeginDropdown(&State->Interface, MakeString("Select"), PanelSelectBtnBounds)) + panel_definition CurrentDef = State->PanelSystem.PanelDefs[Panel->TypeIndex]; + if (ui_BeginDropdown(&State->Interface, MakeString(CurrentDef.PanelName, CurrentDef.PanelNameLength), PanelSelectBtnBounds)) { for (s32 i = 0; i < GlobalPanelDefsCount; i++) { diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 1bd2d16..253f42e 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -587,7 +587,7 @@ PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) internal void DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) { - ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown); + ui_PushLayout(Interface, PanelBounds, LayoutDirection_TopDown, MakeString("AnimClips Layout")); for (s32 i = 0; i < GlobalAnimationClipsCount; i++) { animation_clip Clip = GlobalAnimationClips[i]; @@ -605,7 +605,7 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan { animation_system* AnimSystem = &State->AnimationSystem; ui_interface* Interface = &State->Interface; - ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout")); ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); ui_StartRow(&State->Interface, 4); @@ -792,7 +792,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende animation* ActiveAnim = AnimationSystem_GetActiveAnimation(AnimSystem); ui_interface* Interface = &State->Interface; - ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown); + ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("AnimInfo Layout")); 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 b80ba25..fdf8b54 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -88,7 +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_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("FileView Layout")); if (ui_Button(&State->Interface, MakeString("Exit"))) { diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index d110e17..12c9fc2 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -38,7 +38,7 @@ GSMetaTag(panel_type_hierarchy); internal void HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { - ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown); + ui_PushLayout(&State->Interface, PanelBounds, LayoutDirection_TopDown, MakeString("Hierarchy Layout")); // TODO(pjs): Come back to this after the layout stuff is handled. // Ideally it handles the visuals of the hierarchy itself. diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 7cdf042..d58b3fb 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -179,7 +179,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); - ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown); + ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout")); ui_StartRow(&State->Interface, 4); { diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index f3038f6..90ce10b 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -110,6 +110,8 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.WidgetsCountMax = 4096; State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax); + State->Interface.PerFrameMemory = PushStruct(&State->Permanent, gs_memory_arena); + *State->Interface.PerFrameMemory = CreateMemoryArena(Context.ThreadContext.Allocator); State->SACN = SACN_Initialize(Context); @@ -150,7 +152,6 @@ INITIALIZE_APPLICATION(InitializeApplication) AnimationArray_Push(&State->AnimationSystem.Animations, Anim); } // End Animation Playground - PanelSystem_Init(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount, &State->Permanent); PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); } diff --git a/src/app/interface.h b/src/app/interface.h index 6509468..80b3ada 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -276,6 +276,7 @@ struct ui_widget_retained_state { ui_widget_id Id; bool Value; + u32 FramesSinceAccess; }; struct ui_interface @@ -299,6 +300,8 @@ struct ui_interface #define RETAINED_STATE_MAX 128 ui_widget_retained_state RetainedState[RETAINED_STATE_MAX]; u64 RetainedStateCount; + + gs_memory_arena* PerFrameMemory; }; internal void @@ -307,6 +310,16 @@ ui_InterfaceReset(ui_interface* Interface) Interface->WidgetsCount = 0; Interface->DrawOrderHead = 0; Interface->DrawOrderRoot = 0; + ClearArena(Interface->PerFrameMemory); + + for (u32 i = 0; i < Interface->RetainedStateCount; i++) + { + Interface->RetainedState[i].FramesSinceAccess += 1; + if (Interface->RetainedState[i].FramesSinceAccess > 1) + { + Interface->RetainedState[i] = {0}; + } + } } internal bool @@ -324,6 +337,7 @@ ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) { if (ui_WidgetIdsEqual(Interface->RetainedState[i].Id, Id)) { + Interface->RetainedState[i].FramesSinceAccess = 0; Result = Interface->RetainedState + i; break; } @@ -332,11 +346,11 @@ ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) } internal ui_widget_retained_state* -ui_CreateRetainedState(ui_interface* Interface, ui_widget_id Id) +ui_CreateRetainedState(ui_interface* Interface, ui_widget* Widget) { u64 Index = Interface->RetainedStateCount++; ui_widget_retained_state* Result = Interface->RetainedState + Index; - Result->Id = Id; + Result->Id = Widget->Id; return Result; } @@ -345,6 +359,8 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) { Assert(Interface->WidgetsCount < Interface->WidgetsCountMax); ui_widget* Result = Interface->Widgets + Interface->WidgetsCount++; + ZeroStruct(Result); + Result->Parent = Interface->ActiveLayout; u64 Id = HashDJB2ToU64(StringExpand(String)); @@ -352,10 +368,11 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) { Id = HashAppendDJB2ToU32(Id, Result->Parent->Id.Id); Id = HashAppendDJB2ToU32(Id, Result->Parent->ChildCount); + Result->Id.ParentId = Result->Parent->Id.Id; } Result->Id.Id = Id; - Result->String = String; + Result->String = PushStringCopy(Interface->PerFrameMemory, String.ConstString); Result->Alignment = Align_Left; Result->Next = 0; Result->ChildrenRoot = 0; @@ -364,6 +381,21 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) 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; +} + // // Interaction // @@ -379,13 +411,16 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout static ui_widget* -ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir) +ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { - ui_widget* Result = ui_CreateWidget(Interface, MakeString("Layout")); + ui_widget* Result = ui_CreateWidget(Interface, Name); + ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); + Result->Bounds = Bounds; Result->Margin = Interface->Style.Margin; Result->RowHeight = Interface->Style.RowHeight; Result->FillDirection = FillDir; + switch(FillDir) { case LayoutDirection_BottomUp: @@ -418,7 +453,7 @@ static void ui_PopLayout(ui_interface* Interface) { Assert(Interface->ActiveLayout != 0); - ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds); + //ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds); Interface->ActiveLayout = Interface->ActiveLayout->Parent; } @@ -534,35 +569,14 @@ ui_LayoutRemaining(ui_widget Layout) // Widgets -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); - //u64 Index = Interface->WidgetsCount++; - - Widget->Id.Id = HashDJB2ToU64(StringExpand(Widget->String)); - Widget->Id.ParentId = Interface->ActiveLayout->Id.Id; - Widget->Bounds = Bounds; - //Interface->Widgets[Index] = *Widget; SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget); + Interface->ActiveLayout->ChildCount += 1; if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable)) { @@ -711,7 +725,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E { ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); if (!State) { - State = ui_CreateRetainedState(Interface, Widget->Id); + State = ui_CreateRetainedState(Interface, Widget); } if (EvalResult.Clicked) @@ -747,7 +761,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E }; } - ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction); + ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); Layout->WidgetReference = Widget->Id; } @@ -760,6 +774,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text, rect2 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 ui_EvaluateDropdown(Interface, Widget, Result); } @@ -770,6 +785,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text) 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 ui_EvaluateDropdown(Interface, Widget, Result); } diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 653dbe6..1d2bb65 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -413,7 +413,7 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_ gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256); PrintF(&OutputStr, "Buffers Sent: %d\n", BuffersSent); NullTerminate(&OutputStr); - OutputDebugStringA(OutputStr.Str); + //OutputDebugStringA(OutputStr.Str); } internal void @@ -685,6 +685,10 @@ WinMain ( LastFrameSecondsElapsed = SecondsElapsed; LastFrameEnd = GetWallClock(); + + + OutputDebugStringA("-- Frame END -- \n"); + } Context.CleanupApplication(Context); diff --git a/src/app/platform_win32/win32_foldhaus_work_queue.h b/src/app/platform_win32/win32_foldhaus_work_queue.h index 2db58f3..0b31fa6 100644 --- a/src/app/platform_win32/win32_foldhaus_work_queue.h +++ b/src/app/platform_win32/win32_foldhaus_work_queue.h @@ -46,6 +46,8 @@ Win32CreateThreadContext(gs_memory_arena* Transient = 0) Win32EnumerateDirectory, Result.Transient); + Result.DebugOutput.Print = Win32DebugPrint; + return Result; } diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index a42bdae..f69657c 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -1979,31 +1979,31 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args) if (FormatAt[0] == 'h' && FormatAt[1] == 'h') { LengthSpecified = true; - LengthSpecified = 1; + Length = 1; FormatAt += 2; } else if (FormatAt[0] == 'h') { LengthSpecified = true; - LengthSpecified = 2; + Length = 2; FormatAt++; } else if (FormatAt[0] == 'l' && FormatAt[1] == 'l') { LengthSpecified = true; - LengthSpecified = 8; + Length = 8; FormatAt += 2; } else if (FormatAt[0] == 'l') { LengthSpecified = true; - LengthSpecified = 4; + Length = 4; FormatAt++; } else if (FormatAt[0] == 'j') { LengthSpecified = true; - LengthSpecified = 8; + Length = 8; FormatAt++; } else if (FormatAt[0] == 'z') @@ -2034,7 +2034,7 @@ PrintFArgsList (gs_string* String, char* Format, va_list Args) } else if (FormatAt[0] == 'u') { - u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + u64 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); U64ToASCII(&StringRemaining, UnsignedInt, 10, Base10Chars); } else if (FormatAt[0] == 'o') @@ -2475,6 +2475,19 @@ PushStringF(gs_memory_arena* Arena, u32 MaxLength, char* Format, ...) return Result; } +internal gs_string +PushStringCopy(gs_memory_arena* Arena, gs_const_string String) +{ + gs_string Result = PushString(Arena, String.Length); + Result.Size = String.Length; + Result.Length = String.Length; + for (u32 i = 0; i < String.Length; i++) + { + Result.Str[i] = String.Str[i]; + } + return Result; +} + internal void ClearArena(gs_memory_arena* Arena) { diff --git a/src/todo.txt b/src/todo.txt index 3dcb1f0..c2ef7b1 100644 --- a/src/todo.txt +++ b/src/todo.txt @@ -43,7 +43,6 @@ STREAM #1: 3D Overhaul - :ErrorLogging - Animation System - - blending between animation - layers - layer masks by sculpture - layer masks by tag / value diff --git a/src/todo_done.txt b/src/todo_done.txt index 6aae2d4..ac67406 100644 --- a/src/todo_done.txt +++ b/src/todo_done.txt @@ -1,3 +1,5 @@ +x blending between animation + x saving animation timelines x Buckets & Lists x On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place From e5ab90fcb1b7674507ccadb5e889bfb2e9346a41 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 23:30:24 -0800 Subject: [PATCH 03/10] Did some styling updates to the ui, added a range slider and a toggle --- src/app/editor/foldhaus_editor.cpp | 94 ++++++++---- src/app/interface.h | 168 +++++++++++++++++----- src/app/platform_win32/win32_foldhaus.cpp | 17 ++- src/gs_libs/gs_input.h | 53 ++++--- 4 files changed, 242 insertions(+), 90 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index cd3e5f5..595d53c 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -88,6 +88,36 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } +internal void +Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, v4 Color) +{ + 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; + } +} + internal void Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) { @@ -108,33 +138,39 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && 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) + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, Color); + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) + { + v4 Color = PinkV4; //State->Interface.Style.ButtonColor_Active; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) { - 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; + Color = GreenV4; //State->Interface.Style.ButtonColor_Selected; + } + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) + { + Color = TealV4; //State->Interface.Style.ButtonColor_Selected; + } + + rect2 HFillBounds = {}; + HFillBounds.Min = Widget.Bounds.Min; + HFillBounds.Max = { + LerpR32(Widget.HorizontalFillPercent, Widget.Bounds.Min.x, Widget.Bounds.Max.x), + Widget.Bounds.Max.y + }; + PushRenderQuad2D(RenderBuffer, HFillBounds.Min, HFillBounds.Max, Color); + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + { + // TODO(pjs): Mask this text by the horizontal fill + // TODO(pjs): add this color to the style + v4 TextColor = BlackV4; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, TextColor); } } + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline)) { // TODO(pjs): replace these with values from the style @@ -154,6 +190,11 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren } } +global r32 TestSlider_Value = 5; +global r32 TestSlider_Min = 0; +global r32 TestSlider_Max = 10; +global bool TestToggle = true; + internal void TestRender(app_state* State, context* Context, render_command_buffer* RenderBuffer) { @@ -183,6 +224,11 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_EndDropdown(&State->Interface); } ui_EndRow(&State->Interface); + TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("Test Slider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); + + TestToggle = ui_Toggle(&State->Interface, MakeString("test toggle"), TestToggle); + + ui_Button(&State->Interface, MakeString("Hello")); ui_PopLayout(&State->Interface); @@ -195,7 +241,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 0 +#if 1 TestRender(State, Context, RenderBuffer); //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); diff --git a/src/app/interface.h b/src/app/interface.h index 80b3ada..f9214d1 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -5,14 +5,6 @@ // #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, @@ -188,15 +180,13 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 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_DrawString, UIWidgetFlag_DrawOutline, UIWidgetFlag_Clickable, + UIWidgetFlag_DrawHorizontalFill, }; struct ui_widget_id @@ -223,6 +213,9 @@ struct ui_widget ui_widget* Next; + // Slider + r32 HorizontalFillPercent; + // Layout ui_widget* Parent; @@ -250,6 +243,8 @@ struct ui_widget struct ui_eval_result { bool Clicked; + bool Held; + v2 DragDelta; }; struct interface_config @@ -276,6 +271,7 @@ struct ui_widget_retained_state { ui_widget_id Id; bool Value; + r32 InitialValueR32; u32 FramesSinceAccess; }; @@ -414,7 +410,7 @@ static ui_widget* ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { ui_widget* Result = ui_CreateWidget(Interface, Name); - ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); + //ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); Result->Bounds = Bounds; Result->Margin = Interface->Style.Margin; @@ -425,12 +421,12 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir { case LayoutDirection_BottomUp: { - Result->RowYAt = Bounds.Min.y; + Result->RowYAt = Bounds.Min.y + Result->Margin.y; }break; case LayoutDirection_TopDown: { - Result->RowYAt = Bounds.Max.y - Result->RowHeight; + Result->RowYAt = Bounds.Max.y - (Result->RowHeight + Result->Margin.y); }break; } @@ -447,13 +443,10 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir return Result; } -internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds); - static void ui_PopLayout(ui_interface* Interface) { Assert(Interface->ActiveLayout != 0); - //ui_EvaluateWidget(Interface, Interface->ActiveLayout, Interface->ActiveLayout->Bounds); Interface->ActiveLayout = Interface->ActiveLayout->Parent; } @@ -480,7 +473,7 @@ ui_EndRow(ui_interface* Interface) { Interface->ActiveLayout->DrawHorizontal = false; Interface->ActiveLayout->ColumnWidths = 0; - Interface->ActiveLayout->RowYAt -= Interface->ActiveLayout->RowHeight; + Interface->ActiveLayout->RowYAt -= (Interface->ActiveLayout->RowHeight + Interface->ActiveLayout->Margin.y); } static b32 @@ -489,19 +482,20 @@ ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) b32 Result = true; if (!Widget->DrawHorizontal) { - Bounds->Min = { Widget->Bounds.Min.x, Widget->RowYAt }; - Bounds->Max = { Widget->Bounds.Max.x, Bounds->Min.y + Widget->RowHeight }; + Bounds->Min = { Widget->Bounds.Min.x + Widget->Margin.x, Widget->RowYAt }; + Bounds->Max = { Widget->Bounds.Max.x - Widget->Margin.x, Bounds->Min.y + Widget->RowHeight }; + r32 RowOffset = Widget->RowHeight + Widget->Margin.y; switch (Widget->FillDirection) { case LayoutDirection_BottomUp: { - Widget->RowYAt += Widget->RowHeight; + Widget->RowYAt += RowOffset; }break; case LayoutDirection_TopDown: { - Widget->RowYAt -= Widget->RowHeight; + Widget->RowYAt -= RowOffset; }break; InvalidDefaultCase; @@ -514,13 +508,19 @@ ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) Assert(Widget->ColumnsCount < Widget->ColumnsMax); if (Widget->ColumnWidths != 0) { - v2 Min = { Widget->Bounds.Min.x, Widget->RowYAt }; + v2 Min = { + Widget->Bounds.Min.x + Widget->Margin.x, + Widget->RowYAt + }; for (u32 i = 0; i < Widget->ColumnsCount; i++) { Min.x += Widget->ColumnWidths[i]; } Bounds->Min = Min; - Bounds->Max = Bounds->Min + v2{ Widget->ColumnWidths[Widget->ColumnsCount], Widget->RowHeight }; + Bounds->Max = Bounds->Min + v2{ + Widget->ColumnWidths[Widget->ColumnsCount] - Widget->Margin.x, + Widget->RowHeight + }; } else { @@ -530,7 +530,7 @@ ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) Widget->RowYAt }; Bounds->Max = { - Bounds->Min.x + ElementWidth - Widget->Margin.x, + Bounds->Min.x + ElementWidth - (Widget->Margin.x * 2), Bounds->Min.y + Widget->RowHeight }; } @@ -584,18 +584,27 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) { if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id) && MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) { + Assert(!ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id)); Result.Clicked = true; Interface->ActiveWidget = Widget->Id; } - - if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) && - MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState)) - { - Interface->ActiveWidget = {}; - } - Interface->HotWidget = Widget->Id; } + + + if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState) && + PointIsInRect(Widget->Bounds, Interface->Mouse.DownPos)) + { + Result.Held = true; + Result.DragDelta = Interface->Mouse.Pos - Interface->Mouse.DownPos; + } + + if (ui_WidgetIdsEqual(Interface->ActiveWidget, Widget->Id) && + MouseButtonTransitionedUp(Interface->Mouse.LeftButtonState)) + { + Interface->ActiveWidget = {}; + } + } return Result; @@ -655,24 +664,29 @@ ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Ali ui_EvaluateWidget(Interface, Widget); } -static b32 -ui_Button(ui_interface* Interface, gs_string Text) +internal ui_widget* +ui_CreateButtonWidget(ui_interface* Interface, gs_string Text) { ui_widget* Widget = ui_CreateWidget(Interface, Text); ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); + return Widget; +} + +internal b32 +ui_Button(ui_interface* Interface, gs_string Text) +{ + ui_widget* Widget = ui_CreateButtonWidget(Interface, Text); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); return Result.Clicked; } -static b32 +internal b32 ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds) { - ui_widget* Widget = ui_CreateWidget(Interface, Text); - ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); - ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); - ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_widget* Widget = ui_CreateButtonWidget(Interface, Text); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); return Result.Clicked; } @@ -762,6 +776,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E } ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); + Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; } @@ -775,6 +790,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text, rect2 Bounds) ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); return ui_EvaluateDropdown(Interface, Widget, Result); } @@ -786,6 +802,7 @@ ui_BeginDropdown(ui_interface* Interface, gs_string Text) ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); return ui_EvaluateDropdown(Interface, Widget, Result); } @@ -804,6 +821,79 @@ ui_EndDropdown(ui_interface* Interface) } } +internal r32 +ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_result EvalResult, r32 Value, r32 MinValue, r32 MaxValue) +{ + r32 NewValue = Value; + + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Widget); + } + + if (EvalResult.Clicked) + { + State->InitialValueR32 = Value; + } + + if (EvalResult.Held) + { + r32 Percent = (Interface->Mouse.Pos.x - Widget->Bounds.Min.x) / Rect2Width(Widget->Bounds); + NewValue = LerpR32(Percent, MinValue, MaxValue); + } + + NewValue = Clamp(MinValue, NewValue, MaxValue); + Widget->HorizontalFillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1); + return NewValue; +} + +internal ui_widget* +ui_CreateRangeSliderWidget(ui_interface* Interface, gs_string Text, r32 Value) +{ + ui_widget* Widget = ui_CreateWidget(Interface, Text); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawHorizontalFill); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); + Widget->String = PushStringF(Interface->PerFrameMemory, 128, "%f", Value); + return Widget; +} + +internal r32 +ui_RangeSlider(ui_interface* Interface, gs_string Text, r32 Value, r32 ValueMin, r32 ValueMax) +{ + ui_widget* Widget = ui_CreateRangeSliderWidget(Interface, Text, Value); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget); + return ui_EvaluateRangeSlider(Interface, Widget, Result, Value, ValueMin, ValueMax); + +} + +internal r32 +ui_RangeSlider(ui_interface* Interface, gs_string Text, rect2 Bounds, r32 Value, r32 ValueMin, r32 ValueMax) +{ + ui_widget* Widget = ui_CreateRangeSliderWidget(Interface, Text, Value); + ui_eval_result Result = ui_EvaluateWidget(Interface, Widget, Bounds); + return ui_EvaluateRangeSlider(Interface, Widget, Result, Value, ValueMin, ValueMax); +} + +internal bool +ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) +{ + ui_widget* Widget = ui_CreateWidget(Interface, Text); + ui_WidgetSetFlag(Widget, UIWidgetFlag_Clickable); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawBackground); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawHorizontalFill); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawOutline); + ui_eval_result Eval = ui_EvaluateWidget(Interface, Widget); + + bool Result = Eval.Clicked ? !Value : Value; + Widget->HorizontalFillPercent = Result ? 1.0f : 0.0f; + return Result; +} + + // // OLD // diff --git a/src/app/platform_win32/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp index 1d2bb65..362c898 100644 --- a/src/app/platform_win32/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -187,7 +187,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true, ShiftDown, AltDown, CtrlDown, false); - Mouse->LeftButtonState = KeyState_IsDown & ~KeyState_WasDown; + Mouse->LeftButtonState |= KeyState_IsDown; Mouse->DownPos = Mouse->Pos; // :Win32MouseEventCapture @@ -237,7 +237,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, true, false, ShiftDown, AltDown, CtrlDown, false); - Mouse->LeftButtonState = ~KeyState_IsDown & KeyState_WasDown; + Mouse->LeftButtonState &= ~KeyState_IsDown; // :Win32MouseEventCapture ReleaseCapture(); @@ -593,7 +593,7 @@ WinMain ( AddressedDataBufferList_Clear(&OutputData); - { // Mouse Position + { // Mouse POINT MousePos; GetCursorPos (&MousePos); ScreenToClient(MainWindow.Handle, &MousePos); @@ -602,6 +602,15 @@ WinMain ( Context.Mouse.OldPos = Context.Mouse.Pos; Context.Mouse.Pos = v2{(r32)MousePos.x, (r32)MainWindow.Height - MousePos.y}; Context.Mouse.DeltaPos = Context.Mouse.Pos - Context.Mouse.OldPos; + + if (KeyIsDown(Context.Mouse.LeftButtonState)) + { + SetKeyWasDown(Context.Mouse.LeftButtonState); + } + else + { + SetKeyWasUp(Context.Mouse.LeftButtonState); + } } MSG Message; @@ -687,7 +696,7 @@ WinMain ( LastFrameEnd = GetWallClock(); - OutputDebugStringA("-- Frame END -- \n"); + //OutputDebugStringA("-- Frame END -- \n"); } diff --git a/src/gs_libs/gs_input.h b/src/gs_libs/gs_input.h index d4a83f0..daabf05 100644 --- a/src/gs_libs/gs_input.h +++ b/src/gs_libs/gs_input.h @@ -15,32 +15,32 @@ enum key_code KeyCode_CapsLock, KeyCode_LeftShift, KeyCode_RightShift, KeyCode_LeftCtrl, KeyCode_RightCtrl, - KeyCode_Fn, - KeyCode_Alt, + KeyCode_Fn, + KeyCode_Alt, KeyCode_PageUp, KeyCode_PageDown, KeyCode_Backspace, KeyCode_Delete, KeyCode_Enter, // Function Keys KeyCode_F0, KeyCode_F1, KeyCode_F2, KeyCode_F3, KeyCode_F4, KeyCode_F5, KeyCode_F6, KeyCode_F7, - KeyCode_F8, KeyCode_F9, KeyCode_F10, KeyCode_F11, KeyCode_F12, + KeyCode_F8, KeyCode_F9, KeyCode_F10, KeyCode_F11, KeyCode_F12, // Letters KeyCode_a, KeyCode_b, KeyCode_c, KeyCode_d, KeyCode_e, KeyCode_f, KeyCode_g, KeyCode_h, - KeyCode_i, KeyCode_j, KeyCode_k, KeyCode_l, KeyCode_m, KeyCode_n, KeyCode_o, KeyCode_p, - KeyCode_q, KeyCode_r, KeyCode_s, KeyCode_t, KeyCode_u, KeyCode_v, KeyCode_w, KeyCode_x, + KeyCode_i, KeyCode_j, KeyCode_k, KeyCode_l, KeyCode_m, KeyCode_n, KeyCode_o, KeyCode_p, + KeyCode_q, KeyCode_r, KeyCode_s, KeyCode_t, KeyCode_u, KeyCode_v, KeyCode_w, KeyCode_x, KeyCode_y, KeyCode_z, KeyCode_A, KeyCode_B, KeyCode_C, KeyCode_D, KeyCode_E, KeyCode_F, KeyCode_G, KeyCode_H, - KeyCode_I, KeyCode_J, KeyCode_K, KeyCode_L, KeyCode_M, KeyCode_N, KeyCode_O, KeyCode_P, - KeyCode_Q, KeyCode_R, KeyCode_S, KeyCode_T, KeyCode_U, KeyCode_V, KeyCode_W, KeyCode_X, + KeyCode_I, KeyCode_J, KeyCode_K, KeyCode_L, KeyCode_M, KeyCode_N, KeyCode_O, KeyCode_P, + KeyCode_Q, KeyCode_R, KeyCode_S, KeyCode_T, KeyCode_U, KeyCode_V, KeyCode_W, KeyCode_X, KeyCode_Y, KeyCode_Z, // Numbers KeyCode_0, KeyCode_1, KeyCode_2, KeyCode_3, KeyCode_4, KeyCode_5, KeyCode_6, KeyCode_7, KeyCode_8, KeyCode_9, - KeyCode_Num0, KeyCode_Num1, KeyCode_Num2, KeyCode_Num3, KeyCode_Num4, KeyCode_Num5, + KeyCode_Num0, KeyCode_Num1, KeyCode_Num2, KeyCode_Num3, KeyCode_Num4, KeyCode_Num5, KeyCode_Num6, KeyCode_Num7, KeyCode_Num8, KeyCode_Num9, // Symbols @@ -48,7 +48,7 @@ enum key_code KeyCode_Ampersand, KeyCode_Star, KeyCode_LeftParen, KeyCode_RightParen, KeyCode_Minus, KeyCode_Plus, KeyCode_Equals, KeyCode_Underscore, KeyCode_LeftBrace, KeyCode_RightBrace, KeyCode_LeftBracket, KeyCode_RightBracket, KeyCode_Colon, KeyCode_SemiColon, KeyCode_SingleQuote, KeyCode_DoubleQuote, - KeyCode_ForwardSlash, KeyCode_Backslash, KeyCode_Pipe, KeyCode_Comma, KeyCode_Period, + KeyCode_ForwardSlash, KeyCode_Backslash, KeyCode_Pipe, KeyCode_Comma, KeyCode_Period, KeyCode_QuestionMark, KeyCode_LessThan, KeyCode_GreaterThan, KeyCode_Tilde, KeyCode_BackQuote, // Arrows @@ -77,9 +77,9 @@ CharacterFromKeyCode (key_code Code) case KeyCode_Tab: { Result = '\t'; }break; // Letters - case KeyCode_a: { Result = 'a'; }break; - case KeyCode_b: { Result = 'b'; }break; - case KeyCode_c: { Result = 'c'; }break; + case KeyCode_a: { Result = 'a'; }break; + case KeyCode_b: { Result = 'b'; }break; + case KeyCode_c: { Result = 'c'; }break; case KeyCode_d: { Result = 'd'; }break; case KeyCode_e: { Result = 'e'; }break; case KeyCode_f: { Result = 'f'; }break; @@ -92,7 +92,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_m: { Result = 'm'; }break; case KeyCode_n: { Result = 'n'; }break; case KeyCode_o: { Result = 'o'; }break; - case KeyCode_p: { Result = 'p'; }break; + case KeyCode_p: { Result = 'p'; }break; case KeyCode_q: { Result = 'q'; }break; case KeyCode_r: { Result = 'r'; }break; case KeyCode_s: { Result = 's'; }break; @@ -100,7 +100,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_u: { Result = 'u'; }break; case KeyCode_v: { Result = 'v'; }break; case KeyCode_w: { Result = 'w'; }break; - case KeyCode_x: { Result = 'x'; }break; + case KeyCode_x: { Result = 'x'; }break; case KeyCode_y: { Result = 'y'; }break; case KeyCode_z: { Result = 'z'; }break; @@ -119,7 +119,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_M: { Result = 'M'; }break; case KeyCode_N: { Result = 'N'; }break; case KeyCode_O: { Result = 'O'; }break; - case KeyCode_P: { Result = 'P'; }break; + case KeyCode_P: { Result = 'P'; }break; case KeyCode_Q: { Result = 'Q'; }break; case KeyCode_R: { Result = 'R'; }break; case KeyCode_S: { Result = 'S'; }break; @@ -127,7 +127,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_U: { Result = 'U'; }break; case KeyCode_V: { Result = 'V'; }break; case KeyCode_W: { Result = 'W'; }break; - case KeyCode_X: { Result = 'X'; }break; + case KeyCode_X: { Result = 'X'; }break; case KeyCode_Y: { Result = 'Y'; }break; case KeyCode_Z: { Result = 'Z'; }break; @@ -148,7 +148,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_Num2: { Result = '2'; }break; case KeyCode_Num3: { Result = '3'; }break; case KeyCode_Num4: { Result = '4'; }break; - case KeyCode_Num5: { Result = '5'; }break; + case KeyCode_Num5: { Result = '5'; }break; case KeyCode_Num6: { Result = '6'; }break; case KeyCode_Num7: { Result = '7'; }break; case KeyCode_Num8: { Result = '8'; }break; @@ -181,7 +181,7 @@ CharacterFromKeyCode (key_code Code) case KeyCode_Backslash: { Result = '\\'; }break; case KeyCode_Pipe: { Result = '|'; }break; case KeyCode_Comma: { Result = ','; }break; - case KeyCode_Period: { Result = '.'; }break; + case KeyCode_Period: { Result = '.'; }break; case KeyCode_QuestionMark: { Result = '?'; }break; case KeyCode_LessThan: { Result = '<'; }break; case KeyCode_GreaterThan: { Result = '>'; }break; @@ -227,6 +227,11 @@ enum key_state_flags #define KeyWasDown(event) ((event & KeyState_WasDown) > 0) #define KeyIsDown(event) ((event & KeyState_IsDown) > 0) +#define SetKeyDown(key) (key |= KeyState_IsDown) +#define SetKeyWasDown(key) (key |= KeyState_WasDown) +#define SetKeyUp(key) (key &= ~KeyState_IsDown) +#define SetKeyWasUp(key) (key &= ~KeyState_WasDown) + struct input_entry { key_code Key; @@ -266,6 +271,8 @@ struct mouse_state b32 MiddleButtonState; b32 RightButtonState; + + cursor_type CursorType; }; @@ -327,7 +334,7 @@ KeyTransitionedUp (input Input, key_code Key) } internal void -AddInputEventEntry (input_queue* Queue, key_code Key, +AddInputEventEntry (input_queue* Queue, key_code Key, b32 WasDown, b32 IsDown, b32 ShiftDown, b32 AltDown, b32 CtrlDown, b32 SysDown) { Assert(Queue->QueueUsed < Queue->QueueSize); @@ -392,10 +399,10 @@ GetMouseButtonStateAdvanced (b32 ButtonState) !((ButtonState & KeyState_IsDown) > 0)) { Result= 0; - } - else if (ButtonState & KeyState_IsDown) - { - Result |= KeyState_WasDown; + } + else if (ButtonState & KeyState_IsDown) + { + Result |= KeyState_WasDown; } return Result; } From 1db26150baba2434b1194853ff9108f1d1ea2c4a Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 23:38:56 -0800 Subject: [PATCH 04/10] implemented overlay layouts --- src/app/interface.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/app/interface.h b/src/app/interface.h index f9214d1..785c620 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -406,8 +406,8 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout -static ui_widget* -ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +internal ui_widget* +ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { ui_widget* Result = ui_CreateWidget(Interface, Name); //ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); @@ -430,6 +430,14 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir }break; } + return Result; +} + +static ui_widget* +ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +{ + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); + if (Interface->DrawOrderRoot) { SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Result); @@ -439,6 +447,16 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir { SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); } + + Interface->ActiveLayout = Result; + return Result; +} + +static ui_widget* +ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +{ + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); + SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); Interface->ActiveLayout = Result; return Result; } @@ -775,7 +793,7 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E }; } - ui_widget* Layout = ui_PushLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); + ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; } From 50b6980bec5de9b3149c2f519f79262df31e0df3 Mon Sep 17 00:00:00 2001 From: PS Date: Sat, 14 Nov 2020 23:44:06 -0800 Subject: [PATCH 05/10] ui_DrawString -> ui_Label --- src/app/editor/foldhaus_editor.cpp | 2 +- .../foldhaus_panel_animation_timeline.h | 2 +- .../editor/panels/foldhaus_panel_file_view.h | 2 +- .../editor/panels/foldhaus_panel_profiler.h | 26 +++++++++---------- src/app/interface.h | 12 +++++---- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 595d53c..39460fd 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -241,7 +241,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 1 +#if 0 TestRender(State, Context, RenderBuffer); //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index 253f42e..e9ec1c8 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -798,7 +798,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende ui_StartRow(&State->Interface, 2); { - ui_DrawString(Interface, MakeString("Active Animation")); + ui_Label(Interface, MakeString("Active Animation")); if (ui_BeginDropdown(Interface, ActiveAnim->Name)) { for (u32 i = 0; i < AnimSystem->Animations.Count; i++) diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h index fdf8b54..8183829 100644 --- a/src/app/editor/panels/foldhaus_panel_file_view.h +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -96,7 +96,7 @@ FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBu } // Header - ui_DrawString(&State->Interface, FileViewState->WorkingDirectory); + ui_Label(&State->Interface, FileViewState->WorkingDirectory); // File Display for (u32 i = 0; i < FileViewState->FileNames.Count; i++) diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index d58b3fb..80b7890 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -84,7 +84,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32}); - ui_DrawString(Interface, String, TextBounds); + ui_Label(Interface, String, TextBounds); } } @@ -97,11 +97,11 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb r32 ColumnWidths[] = {256, 128, 128, 128, 128}; ui_StartRow(Interface, 5, &ColumnWidths[0]); { - 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_Label(Interface, MakeString("Procedure")); + ui_Label(Interface, MakeString("% Frame")); + ui_Label(Interface, MakeString("Seconds")); + ui_Label(Interface, MakeString("Cycles")); + ui_Label(Interface, MakeString("Calls")); } ui_EndRow(Interface); @@ -115,19 +115,19 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb ui_StartRow(Interface, 5, &ColumnWidths[0]); { PrintF(&String, "%S", NameEntry.Name); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%fs", CollatedRecord->TotalSeconds); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%dcy", CollatedRecord->TotalCycles); - ui_DrawString(Interface, String); + ui_Label(Interface, String); PrintF(&String, "%d", CollatedRecord->CallCount); - ui_DrawString(Interface, String); + ui_Label(Interface, String); } ui_EndRow(Interface); } @@ -187,10 +187,10 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1; PrintF(&String, "Frame %d", CurrentDebugFrame); - ui_DrawString(&State->Interface, String); + ui_Label(&State->Interface, String); PrintF(&String, "Total Cycles: %lld", FrameTotalCycles); - ui_DrawString(&State->Interface, String); + ui_Label(&State->Interface, String); // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else diff --git a/src/app/interface.h b/src/app/interface.h index 785c620..c2c0b22 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -666,19 +666,20 @@ ui_OutlineRect(ui_interface* Interface, rect2 Bounds, r32 Thickness, v4 Color) } internal void -ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left) +ui_Label(ui_interface* Interface, gs_string String, rect2 Bounds, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; ui_widget* Widget = ui_CreateWidget(Interface, String); - Widget->Bounds = Bounds; - ui_EvaluateWidget(Interface, Widget); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); + ui_EvaluateWidget(Interface, Widget, Bounds); } internal void -ui_DrawString(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left) +ui_Label(ui_interface* Interface, gs_string String, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; ui_widget* Widget = ui_CreateWidget(Interface, String); + ui_WidgetSetFlag(Widget, UIWidgetFlag_DrawString); ui_EvaluateWidget(Interface, Widget); } @@ -756,7 +757,8 @@ 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) { + if (!State) + { State = ui_CreateRetainedState(Interface, Widget); } From 296472a5881968ba1a4c901bd64575c3ac89add9 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 14:48:04 -0800 Subject: [PATCH 06/10] Implemented variable sized row specifications --- src/app/editor/foldhaus_editor.cpp | 98 +++- .../foldhaus_panel_animation_timeline.h | 4 +- .../editor/panels/foldhaus_panel_hierarchy.h | 1 - .../editor/panels/foldhaus_panel_profiler.h | 17 +- src/app/foldhaus_app.cpp | 2 +- src/app/interface.h | 463 ++++++++++++------ 6 files changed, 410 insertions(+), 175 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 39460fd..6fda7e6 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -200,39 +200,86 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff { ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; + State->Interface.WindowBounds = Context->WindowBounds; - ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("TestRender Layout")); + gs_string A = MakeString("TestRender Layout"); - ui_widget_id Ids[2]; - - gs_string String = MakeString("Select"); - ui_StartRow(&State->Interface, 2); - for (u32 j = 0; j < 2; j++) + ui_PushLayout(&State->Interface, A); { - if (ui_BeginDropdown(&State->Interface, String)) +#if 1 + ui_column_spec ColumnRules[] = { + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fill, 0 }, + { UIColumnSize_Percent, .5f } + }; + ui_BeginRow(&State->Interface, 3, ColumnRules); + { - for (u32 i = 0; i < State->PanelSystem.PanelDefsCount; i++) + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + } + ui_EndRow(&State->Interface); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("C")); +#elif 0 + ui_PushLayout(&State->Interface, MakeString("Outer")); + { + for (u32 i = 0; i < 3; i++) { - panel_definition Def = State->PanelSystem.PanelDefs[i]; - gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); - if (ui_Button(&State->Interface, DefName)) - { - - } + ui_Button(&State->Interface, MakeString("A")); } } - ui_EndDropdown(&State->Interface); + ui_PopLayout(&State->Interface); + + ui_BeginRow(&State->Interface, 2); + { + ui_PushLayout(&State->Interface, MakeString("TestLayout")); + { + for (u32 i = 0; i < 5; i++) + { + ui_Button(&State->Interface, MakeString("TestButon")); + } + } + ui_PopLayout(&State->Interface); + + ui_PushLayout(&State->Interface, MakeString("TestLayout")); + { + ui_Button(&State->Interface, MakeString("TestButon")); + TestToggle = ui_Toggle(&State->Interface, MakeString("Toggle"), TestToggle); + TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); + if (ui_BeginDropdown(&State->Interface, MakeString("TestDropdown"))) + { + ui_Button(&State->Interface, MakeString("TestButon")); + ui_Button(&State->Interface, MakeString("TestButon")); + ui_Button(&State->Interface, MakeString("TestButon")); + } + ui_EndDropdown(&State->Interface); + } + ui_PopLayout(&State->Interface); + } + ui_EndRow(&State->Interface); + + ui_PushLayout(&State->Interface, MakeString("Outer")); + { + for (u32 i = 0; i < 3; i++) + { + ui_Button(&State->Interface, MakeString("B")); + } + } + ui_PopLayout(&State->Interface); +#else + ui_BeginList(&State->Interface, MakeString("Test List"), 10); + { + for (u32 i = 0; i < 32; i++) + { + ui_Button(&State->Interface, MakeString("Option")); + } + } + ui_EndList(&State->Interface); +#endif } - ui_EndRow(&State->Interface); - TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("Test Slider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); - - TestToggle = ui_Toggle(&State->Interface, MakeString("test toggle"), TestToggle); - - ui_Button(&State->Interface, MakeString("Hello")); - ui_PopLayout(&State->Interface); - - Assert(!ui_WidgetIdsEqual(Ids[0], Ids[1])); } internal void @@ -243,9 +290,6 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB #if 0 TestRender(State, Context, RenderBuffer); - //ui_widget_id IdTwo = TestRender(State, Context, RenderBuffer); - //Assert(ui_WidgetIdsEqual(IdOne, IdTwo)); - #else ui_InterfaceReset(&State->Interface); State->Interface.RenderBuffer = RenderBuffer; diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h index e9ec1c8..d66b36a 100644 --- a/src/app/editor/panels/foldhaus_panel_animation_timeline.h +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -608,7 +608,7 @@ PlayBar_Render(animation_timeline_state* TimelineState, rect2 Bounds, panel* Pan ui_PushLayout(Interface, Bounds, LayoutDirection_TopDown, MakeString("PlayBar Layout")); ui_FillRect(Interface, Bounds, Interface->Style.PanelBGColors[0]); - ui_StartRow(&State->Interface, 4); + ui_BeginRow(&State->Interface, 4); { if (ui_Button(Interface, MakeString("Pause"))) { @@ -796,7 +796,7 @@ AnimInfoView_Render(animation_timeline_state* TimelineState, rect2 Bounds, rende ui_FillRect(&State->Interface, Bounds, Interface->Style.PanelBGColors[0]); - ui_StartRow(&State->Interface, 2); + ui_BeginRow(&State->Interface, 2); { ui_Label(Interface, MakeString("Active Animation")); if (ui_BeginDropdown(Interface, ActiveAnim->Name)) diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h index 12c9fc2..ec6ca55 100644 --- a/src/app/editor/panels/foldhaus_panel_hierarchy.h +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -52,7 +52,6 @@ HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Ren // Fill in alternating color rows for the backgrounds for (u32 Line = 0; Line < LineCount; Line++) { - //LineBounds[Line] = ui_ReserveElementBounds(Layout); v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line); ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor); } diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 80b7890..f6d1ce8 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -94,8 +94,13 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb char Backbuffer[256]; gs_string String = MakeString(Backbuffer, 0, 256); - r32 ColumnWidths[] = {256, 128, 128, 128, 128}; - ui_StartRow(Interface, 5, &ColumnWidths[0]); + ui_column_spec ColumnWidths[] = { + { UIColumnSize_Fixed, 256 }, + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fixed, 128 }, + { UIColumnSize_Fixed, 128 }}; + ui_BeginRow(Interface, 5, &ColumnWidths[0]); { ui_Label(Interface, MakeString("Procedure")); ui_Label(Interface, MakeString("% Frame")); @@ -112,7 +117,7 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb { collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; - ui_StartRow(Interface, 5, &ColumnWidths[0]); + ui_BeginRow(Interface, 5, &ColumnWidths[0]); { PrintF(&String, "%S", NameEntry.Name); ui_Label(Interface, String); @@ -181,7 +186,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend ui_widget* Layout = ui_PushLayout(&State->Interface, ProcListBounds, LayoutDirection_TopDown, MakeString("Profiler Layout")); - ui_StartRow(&State->Interface, 4); + ui_BeginRow(&State->Interface, 4); { s64 FrameStartCycles = VisibleFrame->FrameStartCycles; s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; @@ -194,7 +199,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else - ui_ReserveElementBounds(Layout); + ui_ReserveBounds(Layout, true); if (ui_Button(&State->Interface, MakeString("Resume Recording"))) { @@ -203,7 +208,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend } ui_EndRow(&State->Interface); - ui_StartRow(&State->Interface, 8); + ui_BeginRow(&State->Interface, 8); { if (ui_Button(&State->Interface, MakeString("Scope View"))) { diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 90ce10b..c56bcaf 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -106,7 +106,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; State->Interface.Style.Margin = v2{5, 5}; - State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface); + State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface) + (2 * State->Interface.Style.Margin.y); State->Interface.WidgetsCountMax = 4096; State->Interface.Widgets = PushArray(&State->Permanent, ui_widget, State->Interface.WidgetsCountMax); diff --git a/src/app/interface.h b/src/app/interface.h index c2c0b22..cc20c18 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -199,6 +199,13 @@ enum ui_layout_direction { LayoutDirection_TopDown, LayoutDirection_BottomUp, + LayoutDirection_Inherit, +}; + +struct ui_column +{ + r32 XMin; + r32 XMax; }; struct ui_widget @@ -225,10 +232,9 @@ struct ui_widget ui_layout_direction FillDirection; - b32 DrawHorizontal; - u32 ColumnsMax; - r32* ColumnWidths; + ui_column* Columns; u32 ColumnsCount; + u32 ColumnsFilled; // NOTE(pjs): I'm not sure this will stay but // its here so that when we end things like a dropdown, @@ -278,7 +284,10 @@ struct ui_widget_retained_state struct ui_interface { interface_config Style; + mouse_state Mouse; + rect2 WindowBounds; + render_command_buffer* RenderBuffer; ui_widget* Widgets; @@ -325,6 +334,28 @@ ui_WidgetIdsEqual(ui_widget_id A, ui_widget_id B) return Result; } +internal void +ui_WidgetSetFlag(ui_widget* Widget, u64 Flag) +{ + u64 Value = ((u64)1 << Flag); + Widget->Flags = Widget->Flags | Value; +} + +internal void +ui_WidgetClearFlag(ui_widget* Widget, u64 Flag) +{ + u64 Value = ((u64)1 << Flag); + Widget->Flags = Widget->Flags & ~Value; +} + +internal bool +ui_WidgetIsFlagSet(ui_widget Widget, u64 Flag) +{ + u64 Value = ((u64)1 << Flag); + bool Result = (Widget.Flags & Value); + return Result; +} + internal ui_widget_retained_state* ui_GetRetainedState(ui_interface* Interface, ui_widget_id Id) { @@ -374,21 +405,7 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) Result->ChildrenRoot = 0; Result->ChildrenHead = 0; Result->Flags = 0; - return Result; -} - -internal void -ui_WidgetSetFlag(ui_widget* Widget, u64 Flag) -{ - u64 Value = ((u64)1 << Flag); - Widget->Flags = Widget->Flags | Value; -} - -internal bool -ui_WidgetIsFlagSet(ui_widget Widget, u64 Flag) -{ - u64 Value = ((u64)1 << Flag); - bool Result = (Widget.Flags & Value); + return Result; } @@ -406,37 +423,146 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout +static rect2 +ui_ReserveBounds(ui_widget* Widget, bool Inset) +{ + Assert(Widget->ColumnsCount > 0); + rect2 Bounds = {0}; + u32 ColumnIndex = Widget->ChildCount % Widget->ColumnsCount; + + ui_column Column = Widget->Columns[ColumnIndex]; + Bounds.Min.x = Column.XMin; + Bounds.Min.y = Widget->RowYAt; + Bounds.Max.x = Column.XMax; + Bounds.Max.y = Bounds.Min.y + Widget->RowHeight; + + if (Inset) + { + Bounds.Min.x += Widget->Margin.x; + Bounds.Min.y += Widget->Margin.y; + Bounds.Max.x -= Widget->Margin.x; + Bounds.Max.y -= Widget->Margin.y; + } + + return Bounds; +} + +internal void +ui_CommitBounds(ui_widget* Parent, rect2 Bounds) +{ + u32 ColumnIndex = Parent->ChildCount % Parent->ColumnsCount; + if (ColumnIndex == 0) + { + switch (Parent->FillDirection) + { + case LayoutDirection_BottomUp: + { + Parent->RowYAt = Bounds.Max.y; + }break; + + case LayoutDirection_TopDown: + { + Parent->RowYAt = Bounds.Min.y - Parent->RowHeight; + }break; + } + } +} + +internal void +ui_ExpandParentToFit(ui_widget* Widget) +{ + ui_widget* Parent = Widget->Parent; + switch (Widget->FillDirection) + { + case LayoutDirection_TopDown: + { + Parent->Bounds.Min.y = Min(Parent->Bounds.Min.y, Widget->Bounds.Min.y - Parent->Margin.y); + }break; + + case LayoutDirection_BottomUp: + { + Parent->Bounds.Max.y = Max(Parent->Bounds.Max.y, Widget->Bounds.Max.y + Parent->Margin.y); + }break; + + InvalidDefaultCase; + } +} + +internal void +ui_WidgetCreateColumns(ui_widget* Widget, u32 ColumnsCount, ui_interface* Interface) +{ + Widget->Columns = PushArray(Interface->PerFrameMemory, ui_column, ColumnsCount); + Widget->ColumnsCount = ColumnsCount; + Widget->ColumnsFilled = 0; +} + +internal void +ui_WidgetInitUniformColumns(ui_widget* Widget) +{ + r32 CurrentRowWidth = Rect2Width(Widget->Bounds); + r32 ColumnWidth = CurrentRowWidth / Widget->ColumnsCount; + for (u32 i = 0; i < Widget->ColumnsCount; i++) + { + ui_column* Column = Widget->Columns + i; + Column->XMin = Widget->Bounds.Min.x + (ColumnWidth * i); + Column->XMax = Column->XMin + ColumnWidth; + } +} + internal ui_widget* -ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +ui_CreateLayoutWidget(ui_interface* Interface, rect2 Bounds, gs_string Name, ui_layout_direction FillDir = LayoutDirection_Inherit) { ui_widget* Result = ui_CreateWidget(Interface, Name); - //ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); + ui_WidgetSetFlag(Result, UIWidgetFlag_DrawOutline); Result->Bounds = Bounds; Result->Margin = Interface->Style.Margin; Result->RowHeight = Interface->Style.RowHeight; - Result->FillDirection = FillDir; - switch(FillDir) + // Single Column Layout + ui_WidgetCreateColumns(Result, 1, Interface); + ui_WidgetInitUniformColumns(Result); + + if (FillDir == LayoutDirection_Inherit && Result->Parent != 0) + { + Result->FillDirection = Result->Parent->FillDirection; + } + else + { + Result->FillDirection = FillDir; + } + + switch(Result->FillDirection) { case LayoutDirection_BottomUp: { - Result->RowYAt = Bounds.Min.y + Result->Margin.y; + Result->RowYAt = Bounds.Min.y; }break; case LayoutDirection_TopDown: { - Result->RowYAt = Bounds.Max.y - (Result->RowHeight + Result->Margin.y); + Result->RowYAt = Bounds.Max.y - Result->RowHeight; }break; + + InvalidDefaultCase; } return Result; } +static ui_widget* +ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +{ + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, Name, FillDir); + SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); + Interface->ActiveLayout = Result; + return Result; +} + static ui_widget* ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) { - ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); + ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, Name, FillDir); if (Interface->DrawOrderRoot) { @@ -453,124 +579,178 @@ ui_PushLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir } static ui_widget* -ui_PushOverlayLayout(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Name) +ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) { - ui_widget* Result = ui_CreateLayoutWidget(Interface, Bounds, FillDir, Name); - SLLPushOrInit(Interface->DrawOrderRoot, Interface->DrawOrderHead, Result); - Interface->ActiveLayout = Result; - return Result; + rect2 Bounds = {}; + ui_layout_direction Direction = LayoutDirection_TopDown; + if (Interface->ActiveLayout) + { + Bounds = ui_ReserveBounds(Interface->ActiveLayout, Inset); + Direction = Interface->ActiveLayout->FillDirection; + } + else + { + Bounds.Min.x = Interface->WindowBounds.Min.x; + Bounds.Min.y = Interface->WindowBounds.Max.y; + Bounds.Max.x = Interface->WindowBounds.Max.x; + Bounds.Max.y = Interface->WindowBounds.Max.y; + + if (Inset) + { + Bounds.Min.x += Interface->Style.Margin.x; + Bounds.Max.x -= Interface->Style.Margin.x; + } + + Direction = LayoutDirection_TopDown; + } + return ui_PushLayout(Interface, Bounds, Direction, Name); +} + +internal void +ui_ExpandToFitChildren(ui_widget* Parent) +{ + v2 Extents = { Parent->Bounds.Max.y, Parent->Bounds.Min.y }; + for (ui_widget* Child = Parent->ChildrenRoot; Child != 0; Child = Child->Next) + { + Extents.x = Min(Extents.x, Child->Bounds.Min.y); + Extents.y = Max(Extents.y, Child->Bounds.Max.y); + } + + switch(Parent->FillDirection) + { + case LayoutDirection_BottomUp: + { + Parent->Bounds.Max.y = Extents.y + Parent->Margin.y; + }break; + + case LayoutDirection_TopDown: + { + Parent->Bounds.Min.y = Extents.x - Parent->Margin.y; + }break; + + InvalidDefaultCase; + } } static void ui_PopLayout(ui_interface* Interface) { Assert(Interface->ActiveLayout != 0); + + ui_widget* Layout = Interface->ActiveLayout; + ui_ExpandToFitChildren(Layout); + Interface->ActiveLayout = Interface->ActiveLayout->Parent; + + // NOTE(pjs): This indicates that the parent layout should + // expand to fit the layout that we just popped + if (Interface->ActiveLayout != 0 && + Interface->ActiveLayout->ChildrenHead == Layout) + { + ui_CommitBounds(Interface->ActiveLayout, Layout->Bounds); + } } static void -ui_StartRow(ui_interface* Interface, u32 ColumnsMax = 0) +ui_BeginRow(ui_interface* Interface, u32 ColumnsMax) { - Interface->ActiveLayout->DrawHorizontal = true; - Interface->ActiveLayout->ColumnsMax = ColumnsMax; - Interface->ActiveLayout->ColumnWidths = 0; - Interface->ActiveLayout->ColumnsCount = 0; + ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); + ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); + ui_WidgetInitUniformColumns(Layout); } -static void -ui_StartRow(ui_interface* Interface, u32 ColumnsMax, r32* ColumnWidths) +enum ui_column_size_rule { - Interface->ActiveLayout->DrawHorizontal = true; - Interface->ActiveLayout->ColumnsMax = ColumnsMax; - Interface->ActiveLayout->ColumnWidths = ColumnWidths; - Interface->ActiveLayout->ColumnsCount = 0; + UIColumnSize_Fixed, + UIColumnSize_Percent, + UIColumnSize_Fill, +}; + +struct ui_column_spec +{ + ui_column_size_rule Rule; + union + { + r32 Width; + r32 Percent; + }; +}; + +static void +ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules) +{ + ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); + ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); + + // First Pass, determine widths of each column, and how much space is left to be divided by the fill columns + r32 RowWidth = Rect2Width(Layout->Bounds); + r32 RemainingSpace = RowWidth; + u32 FillColumnsCount = 0; + for (u32 i = 0; i < Layout->ColumnsCount; i++) + { + ui_column_spec Spec = ColumnRules[i]; + ui_column* Column = Layout->Columns + i; + + switch (Spec.Rule) + { + case UIColumnSize_Fixed: + { + Column->XMax = Spec.Width; + RemainingSpace -= Column->XMax; + }break; + + case UIColumnSize_Percent: + { + Column->XMax = Spec.Percent * RowWidth; + RemainingSpace -= Column->XMax; + }break; + + case UIColumnSize_Fill: + { + FillColumnsCount += 1; + }break; + InvalidDefaultCase; + } + } + + r32 FillColumnWidth = RemainingSpace / FillColumnsCount; + + // Second Pass, specify the actual XMin and XMax of each column + r32 ColumnStartX = Layout->Bounds.Min.x; + for (u32 i = 0; i < Layout->ColumnsCount; i++) + { + ui_column_spec Spec = ColumnRules[i]; + ui_column* Column = Layout->Columns + i; + + r32 ColumnWidth = 0; + switch (Spec.Rule) + { + case UIColumnSize_Fixed: + case UIColumnSize_Percent: + { + ColumnWidth = Column->XMax; + }break; + + case UIColumnSize_Fill: + { + ColumnWidth = FillColumnWidth; + }break; + } + + Column->XMin = ColumnStartX ; + Column->XMax = Column->XMin + Max(0, ColumnWidth); + ColumnStartX = Column->XMax; + } } static void ui_EndRow(ui_interface* Interface) { - Interface->ActiveLayout->DrawHorizontal = false; - Interface->ActiveLayout->ColumnWidths = 0; - Interface->ActiveLayout->RowYAt -= (Interface->ActiveLayout->RowHeight + Interface->ActiveLayout->Margin.y); -} - -static b32 -ui_TryReserveElementBounds(ui_widget* Widget, rect2* Bounds) -{ - b32 Result = true; - if (!Widget->DrawHorizontal) - { - Bounds->Min = { Widget->Bounds.Min.x + Widget->Margin.x, Widget->RowYAt }; - Bounds->Max = { Widget->Bounds.Max.x - Widget->Margin.x, Bounds->Min.y + Widget->RowHeight }; - - r32 RowOffset = Widget->RowHeight + Widget->Margin.y; - switch (Widget->FillDirection) - { - case LayoutDirection_BottomUp: - { - Widget->RowYAt += RowOffset; - }break; - - case LayoutDirection_TopDown: - { - Widget->RowYAt -= RowOffset; - }break; - - InvalidDefaultCase; - } - } - else - { - if (Widget->ColumnsMax > 0) - { - Assert(Widget->ColumnsCount < Widget->ColumnsMax); - if (Widget->ColumnWidths != 0) - { - v2 Min = { - Widget->Bounds.Min.x + Widget->Margin.x, - Widget->RowYAt - }; - for (u32 i = 0; i < Widget->ColumnsCount; i++) - { - Min.x += Widget->ColumnWidths[i]; - } - Bounds->Min = Min; - Bounds->Max = Bounds->Min + v2{ - Widget->ColumnWidths[Widget->ColumnsCount] - Widget->Margin.x, - Widget->RowHeight - }; - } - else - { - r32 ElementWidth = Rect2Width(Widget->Bounds) / Widget->ColumnsMax; - Bounds->Min = { - Widget->Bounds.Min.x + (ElementWidth * Widget->ColumnsCount) + Widget->Margin.x, - Widget->RowYAt - }; - Bounds->Max = { - Bounds->Min.x + ElementWidth - (Widget->Margin.x * 2), - Bounds->Min.y + Widget->RowHeight - }; - } - Widget->ColumnsCount++; - } - else - { - Result = false; - } - } - return Result; -} - -static rect2 -ui_ReserveElementBounds(ui_widget* Layout) -{ - rect2 Bounds = {0}; - if (!ui_TryReserveElementBounds(Layout, &Bounds)) - { - InvalidCodePath; - } - return Bounds; + ui_PopLayout(Interface); + //ui_widget* Layout = Interface->ActiveLayout; + //Layout->DrawHorizontal = false; + //Layout->RowYAt -= (Layout->RowHeight + Layout->Margin.y); + } static rect2 @@ -578,10 +758,6 @@ ui_LayoutRemaining(ui_widget Layout) { rect2 Result = Layout.Bounds; Result.Max.y = Layout.RowYAt; - if (Layout.DrawHorizontal) - { - Result.Max.y -= Layout.RowHeight; - } return Result; } @@ -625,20 +801,17 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) } + Assert(Widget->Parent != 0); + ui_CommitBounds(Widget->Parent, Widget->Bounds); + return Result; } internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget) { - rect2 Bounds = {0}; 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 - InvalidCodePath; - } - + rect2 Bounds = ui_ReserveBounds(Layout, true); return ui_EvaluateWidget(Interface, Widget, Bounds); } @@ -781,8 +954,8 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E r32 ParentLayoutMaxY = ParentLayout.Bounds.Max.y; 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 - ParentLayout.Margin.x, Widget->Bounds.Max.y }, + v2{ Widget->Bounds.Max.x + ParentLayout.Margin.x, ParentLayoutMaxY } }; } else @@ -790,14 +963,15 @@ ui_EvaluateDropdown(ui_interface* Interface, ui_widget* Widget, ui_eval_result E 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 - ParentLayout.Margin.x, ParentLayoutMinY }, + v2{ Widget->Bounds.Max.x + ParentLayout.Margin.x, Widget->Bounds.Min.y } }; } ui_widget* Layout = ui_PushOverlayLayout(Interface, MenuBounds, Direction, MakeString("WidgetLayout")); Layout->Margin.y = 0; Layout->WidgetReference = Widget->Id; + ui_WidgetClearFlag(Layout, UIWidgetFlag_DrawOutline); } return State->Value; @@ -913,6 +1087,19 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) return Result; } +internal void +ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows) +{ + ui_widget* Layout = ui_PushLayout(Interface, Text); + +} + +internal void +ui_EndList(ui_interface* Interface) +{ + +} + // // OLD From 118b734d6c9ac07c7af0b2a7083e5a72c946fdfa Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 16:29:13 -0800 Subject: [PATCH 07/10] Implemented a list view, which included upgrading rendering strings to accept clipping masks --- src/app/editor/foldhaus_editor.cpp | 173 +++++--- .../editor/panels/foldhaus_panel_profiler.h | 2 +- src/app/foldhaus_renderer.h | 15 + src/app/interface.h | 377 +++++++++--------- src/gs_libs/gs_types.cpp | 39 ++ 5 files changed, 352 insertions(+), 254 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 6fda7e6..9d9cce6 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -89,7 +89,7 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue) } internal void -Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, v4 Color) +Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ClippingBox, v4 Color) { render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer, Widget.String.Length, @@ -106,12 +106,12 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe { case Align_Left: { - RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color); + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color); }break; case Align_Right: { - RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, Color); + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(Widget.String), RegisterPosition, State->Interface.Style.Font, ClippingBox, Color); }break; InvalidDefaultCase; @@ -121,62 +121,109 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe internal void Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) { - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground)) + rect2 WidgetParentUnion = Widget.Bounds; + if (Widget.Parent) { - 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); + WidgetParentUnion = Rect2Union(Widget.Bounds, Widget.Parent->Bounds); } - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0)) { - v4 Color = State->Interface.Style.TextColor; - Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, Color); - } - - if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) - { - v4 Color = PinkV4; //State->Interface.Style.ButtonColor_Active; - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground)) { - Color = GreenV4; //State->Interface.Style.ButtonColor_Selected; + 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; + } + PushRenderQuad2DClipped(RenderBuffer, Widget.Bounds, WidgetParentUnion, Color); } - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) - { - Color = TealV4; //State->Interface.Style.ButtonColor_Selected; - } - - rect2 HFillBounds = {}; - HFillBounds.Min = Widget.Bounds.Min; - HFillBounds.Max = { - LerpR32(Widget.HorizontalFillPercent, Widget.Bounds.Min.x, Widget.Bounds.Max.x), - Widget.Bounds.Max.y - }; - PushRenderQuad2D(RenderBuffer, HFillBounds.Min, HFillBounds.Max, Color); if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) { - // TODO(pjs): Mask this text by the horizontal fill - // TODO(pjs): add this color to the style - v4 TextColor = BlackV4; - Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, TextColor); + v4 Color = State->Interface.Style.TextColor; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, Color); + } + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || + ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) + { + v4 Color = State->Interface.Style.ButtonColor_Active; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) + { + Color = State->Interface.Style.ButtonColor_Selected; + } + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) + { + Color = State->Interface.Style.ButtonColor_Selected; + } + + rect2 FillBounds = {}; + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill)) + { + FillBounds.Min.y = Widget.Bounds.Min.y; + FillBounds.Max.y = Widget.Bounds.Max.y; + r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.x, Widget.Bounds.Max.x); + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed)) + { + FillBounds.Min.x = FillToPoint; + FillBounds.Max.x = Widget.Bounds.Max.x; + } + else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle)) + { + FillBounds.Min.x = FillToPoint - 5; + FillBounds.Max.x = FillToPoint + 5; + } + else + { + FillBounds.Min.x = Widget.Bounds.Min.x; + FillBounds.Max.x = FillToPoint; + } + } + else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) + { + FillBounds.Min.x = Widget.Bounds.Min.x; + FillBounds.Max.x = Widget.Bounds.Max.x; + r32 FillToPoint = LerpR32(Widget.FillPercent, Widget.Bounds.Min.y, Widget.Bounds.Max.y); + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillReversed)) + { + FillBounds.Min.y = FillToPoint; + FillBounds.Max.y = Widget.Bounds.Max.y; + } + else if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawFillAsHandle)) + { + FillBounds.Min.y = FillToPoint - 5; + FillBounds.Max.y = FillToPoint + 5; + } + else + { + FillBounds.Min.y = Widget.Bounds.Min.y; + FillBounds.Max.y = FillToPoint; + } + } + PushRenderQuad2D(RenderBuffer, FillBounds.Min, FillBounds.Max, Color); + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) + { + // TODO(pjs): Mask this text by the horizontal fill + // TODO(pjs): add this color to the style + v4 TextColor = BlackV4; + Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, TextColor); + } + } + + + if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawOutline)) + { + // TODO(pjs): replace these with values from the style + r32 Thickness = 1.0f; + v4 Color = WhiteV4; + PushRenderBoundingBox2D(RenderBuffer, WidgetParentUnion.Min, WidgetParentUnion.Max, Thickness, Color); } - } - - - 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) @@ -207,21 +254,29 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_PushLayout(&State->Interface, A); { #if 1 - ui_column_spec ColumnRules[] = { - { UIColumnSize_Fixed, 128 }, - { UIColumnSize_Fill, 0 }, - { UIColumnSize_Percent, .5f } - }; - ui_BeginRow(&State->Interface, 3, ColumnRules); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_Label(&State->Interface, MakeString("Spacer")); + ui_BeginList(&State->Interface, MakeString("TestList"), 5, 9); { ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("B")); + } - ui_EndRow(&State->Interface); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("C")); + ui_EndList(&State->Interface); + //ui_Button(&State->Interface, MakeString("B")); + //ui_Button(&State->Interface, MakeString("C")); + //TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max); #elif 0 ui_PushLayout(&State->Interface, MakeString("Outer")); { @@ -288,7 +343,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 0 +#if 1 TestRender(State, Context, RenderBuffer); #else ui_InterfaceReset(&State->Interface); diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index f6d1ce8..133a0d1 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -199,7 +199,7 @@ ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* Rend // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else - ui_ReserveBounds(Layout, true); + ui_ReserveBounds(&State->Interface, Layout, true); if (ui_Button(&State->Interface, MakeString("Resume Recording"))) { diff --git a/src/app/foldhaus_renderer.h b/src/app/foldhaus_renderer.h index e316c71..a40c0f4 100644 --- a/src/app/foldhaus_renderer.h +++ b/src/app/foldhaus_renderer.h @@ -589,6 +589,21 @@ PushRenderQuad2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color) PushQuad2DOnBatch(&Batch, Min, Max, Color); } +internal void +PushRenderQuad2D (render_command_buffer* Buffer, rect2 Rect, v4 Color) +{ + render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1); + PushQuad2DOnBatch(&Batch, Rect.Min, Rect.Max, Color); +} + +internal void +PushRenderQuad2DClipped (render_command_buffer* Buffer, rect2 Rect, rect2 ClippingBox, v4 Color) +{ + rect2 Clipped = Rect2Union(Rect, ClippingBox); + render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1); + PushQuad2DOnBatch(&Batch, Clipped.Min, Clipped.Max, Color); +} + internal void PushRenderQuad2D(render_command_buffer* Buffer, v2 P0, v2 P1, v2 P2, v2 P3, v4 Color) { diff --git a/src/app/interface.h b/src/app/interface.h index cc20c18..89bdc42 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -13,22 +13,68 @@ enum gs_string_alignment }; internal void -DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 MinY, codepoint_bitmap CodepointInfo, v4 Color) +ClipUVRect(rect2* Bounds, rect2* UVs, rect2 ClippingBox) { + rect2 NewBounds = Rect2Union(*Bounds, ClippingBox); + + r32 OldWidth = Rect2Width(*Bounds); + r32 OldHeight = Rect2Height(*Bounds); + + v2 MinInsetPercent = v2{ + (NewBounds.Min.x - Bounds->Min.x) / OldWidth, + (NewBounds.Min.y - Bounds->Min.y) / OldHeight, + }; + + v2 MaxInsetPercent = v2{ + (NewBounds.Max.x - Bounds->Min.x) / OldWidth, + (NewBounds.Max.y - Bounds->Min.y) / OldHeight, + }; + + UVs->Min.x = LerpR32(MinInsetPercent.x, UVs->Min.x, UVs->Max.x); + UVs->Min.y = LerpR32(MinInsetPercent.y, UVs->Min.y, UVs->Max.y); + UVs->Max.x = LerpR32(MaxInsetPercent.x, UVs->Min.x, UVs->Max.x); + UVs->Max.y = LerpR32(MaxInsetPercent.y, UVs->Min.y, UVs->Max.y); + + *Bounds = NewBounds; +} + +internal void +DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 MinY, codepoint_bitmap CodepointInfo, rect2 ClippingBox, v4 Color) +{ + rect2 Bounds = {}; + Bounds.Min.x = FloorR32(MinX); + Bounds.Min.y = FloorR32(MinY); + Bounds.Max.x = Bounds.Min.x + (CodepointInfo.Width); + Bounds.Max.y = Bounds.Min.y + (CodepointInfo.Height); + + rect2 UVBounds = {}; + UVBounds.Min = CodepointInfo.UVMin; + UVBounds.Max = CodepointInfo.UVMax; + + ClipUVRect(&Bounds, &UVBounds, ClippingBox); + s32 AlignedMinX = (s32)(MinX); s32 AlignedMinY = (s32)(MinY); s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width); s32 AlignedMaxY = AlignedMinY + (CodepointInfo.Height); +#if 1 + PushQuad2DOnBatch(BatchConstructor, + Rect2BottomLeft(Bounds), Rect2BottomRight(Bounds), + Rect2TopRight(Bounds), Rect2TopLeft(Bounds), + UVBounds.Min, UVBounds.Max, + Color); +#else PushQuad2DOnBatch(BatchConstructor, v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY}, CodepointInfo.UVMin, CodepointInfo.UVMax, Color); +#endif } internal v2 -DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, v4 Color) +DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, rect2 ClippingBox, v4 Color) { s32 GlyphDataIndex = GetIndexForCodepoint(Font, C); codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex]; @@ -36,7 +82,7 @@ DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char // NOTE(Peter): r32 MinX = Position.x + CodepointInfo.XOffset; r32 MinY = Position.y + CodepointInfo.YOffset; - DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, Color); + DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, ClippingBox, Color); // NOTE(Peter): v2 PointAfterCharacter = v2{Position.x + CodepointInfo.Width, Position.y}; @@ -44,7 +90,7 @@ DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char } internal v2 -DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, v4 Color) +DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char C, bitmap_font Font, v2 Position, rect2 ClippingBox, v4 Color) { s32 GlyphDataIndex = GetIndexForCodepoint(Font, C); codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex]; @@ -52,7 +98,7 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char // NOTE(Peter): r32 MinX = Position.x - (CodepointInfo.XOffset + CodepointInfo.Width); r32 MinY = Position.y + CodepointInfo.YOffset + CodepointInfo.YOffset; - DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, Color); + DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, ClippingBox, Color); // NOTE(Peter): v2 PointAfterCharacter = v2{Position.x-(CodepointInfo.Width + CodepointInfo.XOffset), Position.y}; @@ -60,13 +106,13 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char } internal v2 -DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, rect2 ClippingBox, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; char* C = gs_string; for (s32 i = 0; i < Length; i++) { - v2 PositionAfterCharacter = DrawCharacterLeftAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); + v2 PositionAfterCharacter = DrawCharacterLeftAligned(BatchConstructor, *C, *Font, RegisterPosition, ClippingBox, Color); RegisterPosition.x = PositionAfterCharacter.x; C++; } @@ -74,13 +120,13 @@ DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Leng } internal v2 -DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, rect2 ClippingBox, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; char* C = gs_string + Length - 1; for (s32 i = Length - 1; i >= 0; i--) { - v2 PositionAfterCharacter = DrawCharacterRightAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); + v2 PositionAfterCharacter = DrawCharacterRightAligned(BatchConstructor, *C, *Font, RegisterPosition, ClippingBox, Color); RegisterPosition.x = PositionAfterCharacter.x; C--; } @@ -101,14 +147,22 @@ DrawString(render_command_buffer* RenderBuffer, gs_string String, bitmap_font* F Font->BitmapBytesPerPixel, Font->BitmapStride); + // TODO(pjs): I don't like this solution but it'll do for now and I want to focus on other problems + // especially since I think this one will go away once I finish the ui overhaul + rect2 InfiniteClipBox = {}; + InfiniteClipBox.Min.x = -100000; + InfiniteClipBox.Min.y = -100000; + InfiniteClipBox.Max.x = 100000; + InfiniteClipBox.Max.y = 100000; + v2 RegisterPosition = Position; if (Alignment == Align_Left) { - RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color); + RegisterPosition = DrawStringLeftAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, InfiniteClipBox, Color); } else if (Alignment == Align_Right) { - RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color); + RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, InfiniteClipBox, Color); } else { @@ -128,6 +182,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col PushQuad2DOnBatch(BatchConstructor, Min, Max, Color); } +#if 0 internal v2 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) { @@ -179,14 +234,19 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 LowerRight.x = RegisterPosition.x; return LowerRight; } +#endif enum ui_widget_flag { + UIWidgetFlag_ExpandsToFitChildren, UIWidgetFlag_DrawBackground, UIWidgetFlag_DrawString, UIWidgetFlag_DrawOutline, UIWidgetFlag_Clickable, UIWidgetFlag_DrawHorizontalFill, + UIWidgetFlag_DrawVerticalFill, + UIWidgetFlag_DrawFillReversed, + UIWidgetFlag_DrawFillAsHandle, }; struct ui_widget_id @@ -221,7 +281,7 @@ struct ui_widget ui_widget* Next; // Slider - r32 HorizontalFillPercent; + r32 FillPercent; // Layout ui_widget* Parent; @@ -279,6 +339,9 @@ struct ui_widget_retained_state bool Value; r32 InitialValueR32; u32 FramesSinceAccess; + + // For use in layouts that allow you to scroll / pan + v2 ChildrenDrawOffset; }; struct ui_interface @@ -381,6 +444,17 @@ ui_CreateRetainedState(ui_interface* Interface, ui_widget* Widget) return Result; } +internal ui_widget_retained_state* +ui_GetOrCreateRetainedState(ui_interface* Interface, ui_widget* Widget) +{ + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Widget); + } + return State; +} + internal ui_widget* ui_CreateWidget(ui_interface* Interface, gs_string String) { @@ -405,6 +479,7 @@ ui_CreateWidget(ui_interface* Interface, gs_string String) Result->ChildrenRoot = 0; Result->ChildrenHead = 0; Result->Flags = 0; + ui_WidgetSetFlag(Result, UIWidgetFlag_ExpandsToFitChildren); return Result; } @@ -424,7 +499,7 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect) // Layout static rect2 -ui_ReserveBounds(ui_widget* Widget, bool Inset) +ui_ReserveBounds(ui_interface* Interface, ui_widget* Widget, bool Inset) { Assert(Widget->ColumnsCount > 0); rect2 Bounds = {0}; @@ -444,6 +519,15 @@ ui_ReserveBounds(ui_widget* Widget, bool Inset) Bounds.Max.y -= Widget->Margin.y; } + if (Widget->ChildCount == 0) + { + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); + if (State) + { + Bounds = Rect2Translate(Bounds, State->ChildrenDrawOffset); + } + } + return Bounds; } @@ -585,7 +669,7 @@ ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) ui_layout_direction Direction = LayoutDirection_TopDown; if (Interface->ActiveLayout) { - Bounds = ui_ReserveBounds(Interface->ActiveLayout, Inset); + Bounds = ui_ReserveBounds(Interface, Interface->ActiveLayout, Inset); Direction = Interface->ActiveLayout->FillDirection; } else @@ -609,6 +693,8 @@ ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true) internal void ui_ExpandToFitChildren(ui_widget* Parent) { + if (!ui_WidgetIsFlagSet(*Parent, UIWidgetFlag_ExpandsToFitChildren)) { return; } + v2 Extents = { Parent->Bounds.Max.y, Parent->Bounds.Min.y }; for (ui_widget* Child = Parent->ChildrenRoot; Child != 0; Child = Child->Next) { @@ -620,12 +706,12 @@ ui_ExpandToFitChildren(ui_widget* Parent) { case LayoutDirection_BottomUp: { - Parent->Bounds.Max.y = Extents.y + Parent->Margin.y; + Parent->Bounds.Max.y = Max(Extents.y + Parent->Margin.y, Parent->Bounds.Max.y); }break; case LayoutDirection_TopDown: { - Parent->Bounds.Min.y = Extents.x - Parent->Margin.y; + Parent->Bounds.Min.y = Min(Extents.x - Parent->Margin.y, Parent->Bounds.Min.y); }break; InvalidDefaultCase; @@ -651,12 +737,13 @@ ui_PopLayout(ui_interface* Interface) } } -static void +static ui_widget* ui_BeginRow(ui_interface* Interface, u32 ColumnsMax) { ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); ui_WidgetInitUniformColumns(Layout); + return Layout; } enum ui_column_size_rule @@ -676,13 +763,14 @@ struct ui_column_spec }; }; -static void +static ui_widget* ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules) { ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false); ui_WidgetCreateColumns(Layout, ColumnsMax, Interface); // First Pass, determine widths of each column, and how much space is left to be divided by the fill columns + // If a size is specified, it is stored in Column->XMax r32 RowWidth = Rect2Width(Layout->Bounds); r32 RemainingSpace = RowWidth; u32 FillColumnsCount = 0; @@ -741,16 +829,14 @@ ui_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules Column->XMax = Column->XMin + Max(0, ColumnWidth); ColumnStartX = Column->XMax; } + + return Layout; } static void ui_EndRow(ui_interface* Interface) { ui_PopLayout(Interface); - //ui_widget* Layout = Interface->ActiveLayout; - //Layout->DrawHorizontal = false; - //Layout->RowYAt -= (Layout->RowHeight + Layout->Margin.y); - } static rect2 @@ -771,10 +857,12 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) Widget->Bounds = Bounds; SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget); Interface->ActiveLayout->ChildCount += 1; + ui_CommitBounds(Widget->Parent, Widget->Bounds); if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable)) { - if (PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) + if (PointIsInRect(Widget->Parent->Bounds, Interface->Mouse.Pos) && + PointIsInRect(Widget->Bounds, Interface->Mouse.Pos)) { if (ui_WidgetIdsEqual(Interface->HotWidget, Widget->Id) && MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) { @@ -785,7 +873,6 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) Interface->HotWidget = Widget->Id; } - if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState) && PointIsInRect(Widget->Bounds, Interface->Mouse.DownPos)) { @@ -802,8 +889,6 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds) } Assert(Widget->Parent != 0); - ui_CommitBounds(Widget->Parent, Widget->Bounds); - return Result; } @@ -811,7 +896,7 @@ internal ui_eval_result ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget) { ui_widget* Layout = Interface->ActiveLayout; - rect2 Bounds = ui_ReserveBounds(Layout, true); + rect2 Bounds = ui_ReserveBounds(Interface, Layout, true); return ui_EvaluateWidget(Interface, Widget, Bounds); } @@ -1019,12 +1104,7 @@ internal r32 ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_result EvalResult, r32 Value, r32 MinValue, r32 MaxValue) { r32 NewValue = Value; - - ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id); - if (!State) - { - State = ui_CreateRetainedState(Interface, Widget); - } + ui_widget_retained_state* State = ui_GetOrCreateRetainedState(Interface, Widget); if (EvalResult.Clicked) { @@ -1038,7 +1118,7 @@ ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_resul } NewValue = Clamp(MinValue, NewValue, MaxValue); - Widget->HorizontalFillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1); + Widget->FillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1); return NewValue; } @@ -1083,21 +1163,86 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) ui_eval_result Eval = ui_EvaluateWidget(Interface, Widget); bool Result = Eval.Clicked ? !Value : Value; - Widget->HorizontalFillPercent = Result ? 1.0f : 0.0f; + Widget->FillPercent = Result ? 1.0f : 0.0f; return Result; } internal void -ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows) +ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 ElementCount) { - ui_widget* Layout = ui_PushLayout(Interface, Text); + ui_column_spec ColumnRules[] = { + { UIColumnSize_Fixed, 32 }, + { UIColumnSize_Fill, 0 }, + }; + ui_widget* Layout = ui_BeginRow(Interface, 2, ColumnRules); + ui_WidgetClearFlag(Layout, UIWidgetFlag_ExpandsToFitChildren); + ui_widget_retained_state* State = ui_GetRetainedState(Interface, Layout->Id); + if (!State) + { + State = ui_CreateRetainedState(Interface, Layout); + State->InitialValueR32 = 1.0f; + } + + r32 LayoutHeight = Layout->RowHeight * ViewportRows; + switch (Layout->Parent->FillDirection) + { + case LayoutDirection_TopDown: + { + Layout->Bounds.Min.y = Layout->Bounds.Max.y - LayoutHeight; + }break; + + case LayoutDirection_BottomUp: + { + Layout->Bounds.Max.y = Layout->Bounds.Min.y + LayoutHeight; + }break; + + InvalidDefaultCase; + } + + // Create the scroll bar + // + + ui_widget* SliderRegion = ui_CreateWidget(Interface, MakeString("Slider")); + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawOutline); + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawVerticalFill); + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawFillAsHandle); + + ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_Clickable); + + rect2 SliderBounds = ui_ReserveBounds(Interface, Layout, true); + SliderBounds.Min.y = Layout->Bounds.Min.y + Layout->Margin.y; + SliderBounds.Max.y = Layout->Bounds.Max.y - Layout->Margin.y; + + ui_eval_result SliderEval = ui_EvaluateWidget(Interface, SliderRegion, SliderBounds); + if (SliderEval.Clicked || SliderEval.Held) + { + r32 Percent = (Interface->Mouse.Pos.y - SliderRegion->Bounds.Min.y) / Rect2Height(SliderRegion->Bounds); + State->InitialValueR32 = Clamp01(Percent); + } + SliderRegion->FillPercent = State->InitialValueR32; + + // Create the viewport that offsets list contents (and at render time determines what is visible) + // + ui_widget* ViewportLayout = ui_PushLayout(Interface, MakeString("Contents")); + ui_WidgetClearFlag(ViewportLayout, UIWidgetFlag_ExpandsToFitChildren); + + ViewportLayout->Bounds.Min.y = SliderBounds.Min.y; + ViewportLayout->Bounds.Max.y = SliderBounds.Max.y; + + ui_widget_retained_state* ViewportState = ui_GetOrCreateRetainedState(Interface, ViewportLayout); + ViewportState->ChildrenDrawOffset.x = 0; + ViewportState->ChildrenDrawOffset.y = ((1.0f - State->InitialValueR32) * (r32)(ElementCount - ViewportRows)) * ViewportLayout->RowHeight; } internal void ui_EndList(ui_interface* Interface) { - + // Pop the Viewport Layout + ui_PopLayout(Interface); + // TODO(pjs): Ensure that the active layout is the row layout we started in begin list + // Pop the actual list layout + ui_EndRow(Interface); } @@ -1105,60 +1250,6 @@ ui_EndList(ui_interface* Interface) // OLD // -enum selection_state -{ - Selection_None, - Selection_Selected, - Selection_Deselected, -}; - -struct interface_list -{ - rect2 ListBounds; - - v2 ListElementDimensions; - v2 ElementLabelIndent; - - v4 TextColor; - v4* LineBGColors; - s32 LineBGColorsCount; - v4 LineBGHoverColor; - - s32 ListElementsCount; -}; - -internal rect2 -DrawListElementBackground(interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer) -{ - rect2 LineBounds = {}; - LineBounds.Min = v2{ - List->ListBounds.Min.x, - List->ListBounds.Max.y - (List->ListElementDimensions.y * (List->ListElementsCount + 1)) - }; - LineBounds.Max = LineBounds.Min + List->ListElementDimensions; - - v4 Color = List->LineBGColors[List->ListElementsCount % List->LineBGColorsCount]; - if (PointIsInRect(LineBounds, Mouse.Pos)) - { - Color = List->LineBGHoverColor; - } - - PushRenderQuad2D(RenderBuffer, LineBounds.Min, LineBounds.Max, Color); - return LineBounds; -} - -internal rect2 -DrawListElement(gs_string Label, interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer, interface_config Interface) -{ - rect2 Bounds = DrawListElementBackground(List, Mouse, RenderBuffer); - - v2 LabelPosition = Bounds.Min + List->ElementLabelIndent; - DrawString(RenderBuffer, Label, Interface.Font, LabelPosition, List->TextColor); - - List->ListElementsCount++; - return Bounds; -} - internal r32 EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, v2 Min, v2 Max, r32 Current, mouse_state Mouse) @@ -1200,107 +1291,5 @@ EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, return Result; } -internal b32 -EvaluateColorPicker (render_command_buffer* RenderBuffer, v4* Value, v2 PanelMin, interface_config Config, mouse_state Mouse) -{ - b32 ShouldClose = false; - - v2 PanelMax = v2{400, 500}; - // TODO(Peter): Can this get passed from outside? rather pass rect2 than min/max pairs - rect2 PanelRect = rect2{PanelMin, PanelMax}; - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRect(PanelRect, Mouse.Pos)) - { - ShouldClose = true; - } - else - { - PushRenderQuad2D(RenderBuffer, PanelRect.Min, PanelRect.Max, v4{.5f, .5f, .5f, 1.f}); - - v2 TitleMin = v2{PanelRect.Min.x + 5, PanelRect.Max.y - (Config.Font->PixelHeight + 5)}; - DrawString(RenderBuffer, MakeString("Color Picker"), Config.Font, - TitleMin, WhiteV4); - - v2 SliderDim = v2{(PanelMax.x - PanelMin.x) - 20, 32}; - // channel sliders - v2 SliderMin = TitleMin - v2{0, SliderDim.y + 10}; - Value->r = EvaluateColorChannelSlider(RenderBuffer, RedV4, SliderMin, SliderMin + SliderDim, Value->r, Mouse); - SliderMin.y -= SliderDim.y + 10; - Value->g = EvaluateColorChannelSlider(RenderBuffer, GreenV4, SliderMin, SliderMin + SliderDim, Value->g, Mouse); - SliderMin.y -= SliderDim.y + 10; - Value->b = EvaluateColorChannelSlider(RenderBuffer, BlueV4, SliderMin, SliderMin + SliderDim, Value->b, Mouse); - SliderMin.y -= SliderDim.y + 10; - Value->a = EvaluateColorChannelSlider(RenderBuffer, WhiteV4, SliderMin, SliderMin + SliderDim, Value->a, Mouse); - - // Output Color Display - SliderMin.y -= 100; - PushRenderQuad2D(RenderBuffer, SliderMin, SliderMin + v2{75, 75}, *Value); - } - - return ShouldClose; -} - -struct search_lister_result -{ - s32 HotItem; - s32 SelectedItem; - b32 ShouldRemainOpen; -}; - -typedef gs_string search_lister_get_list_item_at_offset(u8* ListMemory, s32 ListLength, gs_string Searchgs_string, s32 Offset); - -internal search_lister_result -EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, gs_string Title, - gs_string* ItemList, s32* ListLUT, s32 ListLength, - s32 HotItem, - gs_string* Searchgs_string, s32 Searchgs_stringCursorPosition) -{ - search_lister_result Result = {}; - Result.ShouldRemainOpen = true; - Result.HotItem = HotItem; - - // TODO(Peter): Was tired. Nothing wrong with the code below - InvalidCodePath; -#if 0 - // Title Bar - rect2 TitleBarBounds = rect2{v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}}; - ui_FillRect(Interface, TitleBarBounds, v4{.3f, .3f, .3f, 1.f}); - ui_Drawgs_string(Interface, Title, TitleBarBounds, Interface->Style.TextColor); - - MakeStringBuffer(Debuggs_string, 256); - PrintF(&Debuggs_string, "Hot Item: %d | Filtered Items: %d", HotItem, ListLength); - rect2 DebugBounds = MakeRectMinWidth(v2{ TopLeft.x + 256, TopLeft.y - 25}, v2{256, Interface->Style.LineHeight}); - ui_Drawgs_string(Interface, Debuggs_string, DebugBounds, Interface->Style.TextColor); - - // Search Bar - PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f}); - Drawgs_stringWithCursor(RenderBuffer, *Searchgs_string, Searchgs_stringCursorPosition, Font, v2{TopLeft.x, TopLeft.y - 25}, WhiteV4, GreenV4); - TopLeft.y -= 30; - - for (s32 i = 0; i < ListLength; i++) - { - s32 FilteredIndex = ListLUT[i]; - gs_string ListItemgs_string = ItemList[FilteredIndex]; - - v2 Min = v2{TopLeft.x, TopLeft.y - 30}; - v2 Max = Min + Dimension - v2{0, Config.Margin.y}; - - v4 ButtonColor = Config.ButtonColor_Inactive; - if (i == HotItem) - { - ButtonColor = Config.ButtonColor_Active; - } - - if (ui_Button(Interface, ListItemgs_string, rect2{Min, Max})) - { - Result.SelectedItem = i; - } - - TopLeft.y -= 30; - } -#endif - - return Result; -} - #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp index f69657c..cdd6252 100644 --- a/src/gs_libs/gs_types.cpp +++ b/src/gs_libs/gs_types.cpp @@ -927,6 +927,10 @@ Range2Union(range2 A, range2 B) Result.Min.y = Max(A.Min.y, B.Min.y); Result.Max.x = Min(A.Max.x, B.Max.x); Result.Max.y = Min(A.Max.y, B.Max.y); + + if (Rect2Width(Result) < 0) { Result.Min.x = Result.Max.x; } + if (Rect2Height(Result) < 0) { Result.Min.y = Result.Max.y; } + return Result; } internal range3 @@ -949,6 +953,41 @@ Rect2GetRectLocalPoint(rect2 Rect, v2 Point) return Result; } +internal r32 +Rect2Area(rect2 Rect) +{ + r32 Result = Rect2Width(Rect) * Rect2Height(Rect); + return Result; +} + +internal v2 +Rect2BottomLeft(rect2 Rect) +{ + v2 Result = Rect.Min; + return Result; +} + +internal v2 +Rect2BottomRight(rect2 Rect) +{ + v2 Result = v2{ Rect.Max.x, Rect.Min.y }; + return Result; +} + +internal v2 +Rect2TopRight(rect2 Rect) +{ + v2 Result = Rect.Max; + return Result; +} + +internal v2 +Rect2TopLeft(rect2 Rect) +{ + v2 Result = v2{ Rect.Min.x, Rect.Max.y }; + return Result; +} + /////////////////////////// // // Ray From 91b2b822f9b1d7f82fe540d83055d54983ec7b18 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 16:36:11 -0800 Subject: [PATCH 08/10] did a few more tweaks to teh list --- src/app/editor/foldhaus_editor.cpp | 21 +++------- src/app/interface.h | 62 ++++-------------------------- 2 files changed, 14 insertions(+), 69 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 9d9cce6..e28480a 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -152,14 +152,11 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawHorizontalFill) || ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawVerticalFill)) { - v4 Color = State->Interface.Style.ButtonColor_Active; - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget)) + v4 Color = State->Interface.Style.ButtonColor_Selected; + if (ui_WidgetIdsEqual(Widget.Id, State->Interface.HotWidget) || + ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) { - Color = State->Interface.Style.ButtonColor_Selected; - } - if (ui_WidgetIdsEqual(Widget.Id, State->Interface.ActiveWidget)) - { - Color = State->Interface.Style.ButtonColor_Selected; + Color = WhiteV4; } rect2 FillBounds = {}; @@ -205,7 +202,7 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren FillBounds.Max.y = FillToPoint; } } - PushRenderQuad2D(RenderBuffer, FillBounds.Min, FillBounds.Max, Color); + PushRenderQuad2DClipped(RenderBuffer, FillBounds, WidgetParentUnion, Color); if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0) { @@ -260,18 +257,12 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_Label(&State->Interface, MakeString("Spacer")); ui_Label(&State->Interface, MakeString("Spacer")); - ui_BeginList(&State->Interface, MakeString("TestList"), 5, 9); + ui_BeginList(&State->Interface, MakeString("TestList"), 5, 4); { ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - } ui_EndList(&State->Interface); //ui_Button(&State->Interface, MakeString("B")); diff --git a/src/app/interface.h b/src/app/interface.h index 89bdc42..b66b771 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -58,19 +58,11 @@ DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 M s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width); s32 AlignedMaxY = AlignedMinY + (CodepointInfo.Height); -#if 1 PushQuad2DOnBatch(BatchConstructor, Rect2BottomLeft(Bounds), Rect2BottomRight(Bounds), Rect2TopRight(Bounds), Rect2TopLeft(Bounds), UVBounds.Min, UVBounds.Max, Color); -#else - PushQuad2DOnBatch(BatchConstructor, - v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY}, - v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY}, - CodepointInfo.UVMin, CodepointInfo.UVMax, - Color); -#endif } internal v2 @@ -1170,6 +1162,11 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value) internal void ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 ElementCount) { + if (ElementCount < ViewportRows) + { + ViewportRows = ElementCount; + } + ui_column_spec ColumnRules[] = { { UIColumnSize_Fixed, 32 }, { UIColumnSize_Fill, 0 }, @@ -1202,6 +1199,7 @@ ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 Elem // Create the scroll bar // + // TODO(pjs): Maybe make this a vertical slider widget? ui_widget* SliderRegion = ui_CreateWidget(Interface, MakeString("Slider")); ui_WidgetSetFlag(SliderRegion, UIWidgetFlag_DrawOutline); @@ -1230,9 +1228,10 @@ ui_BeginList(ui_interface* Interface, gs_string Text, u32 ViewportRows, u32 Elem ViewportLayout->Bounds.Min.y = SliderBounds.Min.y; ViewportLayout->Bounds.Max.y = SliderBounds.Max.y; + s32 ScrollableElements = Max(0, ElementCount - ViewportRows); ui_widget_retained_state* ViewportState = ui_GetOrCreateRetainedState(Interface, ViewportLayout); ViewportState->ChildrenDrawOffset.x = 0; - ViewportState->ChildrenDrawOffset.y = ((1.0f - State->InitialValueR32) * (r32)(ElementCount - ViewportRows)) * ViewportLayout->RowHeight; + ViewportState->ChildrenDrawOffset.y = ((1.0f - State->InitialValueR32) * (r32)(ScrollableElements)) * ViewportLayout->RowHeight; } internal void @@ -1246,50 +1245,5 @@ ui_EndList(ui_interface* Interface) } -// -// OLD -// - - -internal r32 -EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, v2 Min, v2 Max, r32 Current, mouse_state Mouse) -{ - r32 Result = Current; - - // TODO(Peter): Can this come from outside the function? Would rather pass rect around than min/max - rect2 Rect = rect2{ Min, Max }; - - render_quad_batch_constructor Batch = PushRenderQuad2DBatch(RenderBuffer, 2); - - v4 LeftColor = ChannelMask * 0; - LeftColor.a = 1.f; - v4 RightColor = ChannelMask; - PushQuad2DOnBatch(&Batch, - RectBottomLeft(Rect), RectBottomRight(Rect), - RectTopRight(Rect), RectTopLeft(Rect), - v2{0, 0}, v2{1, 0}, v2{1, 1}, v2{0, 1}, - LeftColor, RightColor, RightColor, LeftColor); - - if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) - { - if (PointIsInRect(Rect, Mouse.DownPos)) - { - Result = ((r32)Mouse.Pos.x - Min.x) / (Max.x - Min.x); - Result = Clamp01(Result); - } - } - - r32 DragBarWidth = 8; - v2 DragBarMin = v2{ - LerpR32(Result, Min.x, Max.x) - (DragBarWidth / 2), - Min.y - 2 - }; - v2 DragBarMax = DragBarMin + v2{DragBarWidth, (Max.y - Min.y) + 4}; - - PushQuad2DOnBatch(&Batch, DragBarMin, DragBarMax, v4{.3f, .3f, .3f, 1.f}); - - return Result; -} - #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file From 8d737fd961b85b84591abb335545ad1f2515b324 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 16:58:13 -0800 Subject: [PATCH 09/10] made the profiler list view a ui list --- src/app/editor/foldhaus_editor.cpp | 30 ++++++------ .../editor/panels/foldhaus_panel_profiler.h | 46 +++++++++++-------- src/app/foldhaus_debug.h | 4 ++ 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index e28480a..067b4e6 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -119,13 +119,10 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe } internal void -Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget) +Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* RenderBuffer, ui_widget Widget, rect2 ParentClipBounds) { rect2 WidgetParentUnion = Widget.Bounds; - if (Widget.Parent) - { - WidgetParentUnion = Rect2Union(Widget.Bounds, Widget.Parent->Bounds); - } + WidgetParentUnion = Rect2Union(Widget.Bounds, ParentClipBounds); if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0)) { @@ -225,12 +222,12 @@ Editor_DrawWidget(app_state* State, context* Context, render_command_buffer* Ren if (Widget.ChildrenRoot) { - Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot); + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.ChildrenRoot, WidgetParentUnion); } if (Widget.Next) { - Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next); + Editor_DrawWidget(State, Context, RenderBuffer, *Widget.Next, ParentClipBounds); } } @@ -257,12 +254,17 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff ui_Label(&State->Interface, MakeString("Spacer")); ui_Label(&State->Interface, MakeString("Spacer")); - ui_BeginList(&State->Interface, MakeString("TestList"), 5, 4); + ui_BeginList(&State->Interface, MakeString("TestList"), 5, 16); { - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); - ui_Button(&State->Interface, MakeString("B")); + ui_BeginRow(&State->Interface, 3); + for (u32 i = 0; i < 16; i++) + { + + ui_Button(&State->Interface, MakeString("B")); + ui_Button(&State->Interface, MakeString("C")); + ui_Button(&State->Interface, MakeString("D")); + } + ui_EndRow(&State->Interface); } ui_EndList(&State->Interface); //ui_Button(&State->Interface, MakeString("B")); @@ -334,7 +336,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); -#if 1 +#if 0 TestRender(State, Context, RenderBuffer); #else ui_InterfaceReset(&State->Interface); @@ -359,7 +361,7 @@ Editor_Render(app_state* State, context* Context, render_command_buffer* RenderB if (State->Interface.DrawOrderRoot != 0) { ui_widget Widget = *State->Interface.DrawOrderRoot; - Editor_DrawWidget(State, Context, RenderBuffer, Widget); + Editor_DrawWidget(State, Context, RenderBuffer, Widget, Context->WindowBounds); } Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 133a0d1..0268ef0 100644 --- a/src/app/editor/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -110,6 +110,18 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb } ui_EndRow(Interface); + s32 CountedScopes = 0; + for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) + { + scope_name NameEntry = VisibleFrame->ScopeNamesHash[n]; + if (NameEntry.Hash != 0) + { + CountedScopes += 1; + } + } + + ui_BeginList(Interface, MakeString("Scope List"), 10, CountedScopes); + ui_BeginRow(Interface, 5, &ColumnWidths[0]); for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) { scope_name NameEntry = VisibleFrame->ScopeNamesHash[n]; @@ -117,26 +129,24 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_widget* Layout, deb { collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; - ui_BeginRow(Interface, 5, &ColumnWidths[0]); - { - PrintF(&String, "%S", NameEntry.Name); - ui_Label(Interface, String); - - PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); - ui_Label(Interface, String); - - PrintF(&String, "%fs", CollatedRecord->TotalSeconds); - ui_Label(Interface, String); - - PrintF(&String, "%dcy", CollatedRecord->TotalCycles); - ui_Label(Interface, String); - - PrintF(&String, "%d", CollatedRecord->CallCount); - ui_Label(Interface, String); - } - ui_EndRow(Interface); + PrintF(&String, "%S", NameEntry.Name); + ui_Label(Interface, String); + + PrintF(&String, "%f%%", CollatedRecord->PercentFrameTime); + ui_Label(Interface, String); + + PrintF(&String, "%fs", CollatedRecord->TotalSeconds); + ui_Label(Interface, String); + + PrintF(&String, "%dcy", CollatedRecord->TotalCycles); + ui_Label(Interface, String); + + PrintF(&String, "%d", CollatedRecord->CallCount); + ui_Label(Interface, String); } } + ui_EndRow(Interface); + ui_EndList(Interface); } GSMetaTag(panel_render); diff --git a/src/app/foldhaus_debug.h b/src/app/foldhaus_debug.h index ca26188..7acdfcc 100644 --- a/src/app/foldhaus_debug.h +++ b/src/app/foldhaus_debug.h @@ -54,6 +54,7 @@ struct debug_frame s64 FrameEndCycles; s32 ScopeNamesMax; + s32 ScopeNamesCount; scope_name* ScopeNamesHash; s32 ThreadCount; @@ -302,6 +303,7 @@ EndDebugFrame (debug_services* Services) CollateThreadScopeCalls(ClosingFrame->ThreadCalls + t, ClosingFrame); } + s32 ScopeNamesCount = 0; for (s32 n = 0; n < ClosingFrame->ScopeNamesMax; n++) { if (ClosingFrame->ScopeNamesHash[n].Hash != 0) @@ -310,8 +312,10 @@ EndDebugFrame (debug_services* Services) CollatedRecord->TotalSeconds = (r32)CollatedRecord->TotalCycles / (r32)Services->PerformanceCountFrequency; CollatedRecord->PercentFrameTime = (r32)CollatedRecord->TotalCycles / (r32)FrameTotalCycles; CollatedRecord->AverageSecondsPerCall = CollatedRecord->TotalSeconds / CollatedRecord->CallCount; + ScopeNamesCount += 1; } } + ClosingFrame->ScopeNamesCount = ScopeNamesCount; Services->CurrentDebugFrame = (Services->CurrentDebugFrame + 1) % DEBUG_FRAME_COUNT; StartDebugFrame(&Services->Frames[Services->CurrentDebugFrame], Services); From 6e2405198245b06db688c2be9d4325f20b8c8db6 Mon Sep 17 00:00:00 2001 From: PS Date: Sun, 15 Nov 2020 17:07:59 -0800 Subject: [PATCH 10/10] Added a mouse hover layout and used it in the profiler --- .../editor/panels/foldhaus_panel_profiler.h | 25 +++++++------------ src/app/interface.h | 13 ++++++++++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/app/editor/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h index 0268ef0..3a49177 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_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) +RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, debug_frame* VisibleFrame, gs_memory_arena* Transient) { v4 ThreadColors[] = { v4{.73f, .33f, .83f, 1}, @@ -45,11 +45,7 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices, VisibleFrame); - scope_record* HotRecord = 0; - scope_name* HotRecordName = 0; - - char Backbuffer[256]; - gs_string String = MakeString(Backbuffer, 0, 256); + gs_string String = PushString(Transient, 256); for (s32 i = 0; i < ThreadScopeCalls->Count; i++) { scope_record* Record = ThreadScopeCalls->Calls + i; @@ -70,22 +66,19 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_widget* Layout, de if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos)) { Color = GreenV4; - HotRecord = Record; - HotRecordName = Name; + + ui_BeginMousePopup(Interface, rect2{ 25, 25, 300, 57 }, LayoutDirection_TopDown, MakeString("Hover")); + { + PrintF(&String, "%S : %d - %d", Name->Name, Record->StartCycles, Record->EndCycles); + ui_Label(Interface, String); + } + ui_EndMousePopup(Interface); } ui_FillRect(Interface, ScopeBounds, Color); ui_OutlineRect(Interface, ScopeBounds, 1, BlackV4); } } - - if (HotRecord != 0) - { - PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); - - rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32}); - ui_Label(Interface, String, TextBounds); - } } internal void diff --git a/src/app/interface.h b/src/app/interface.h index b66b771..3cd2772 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -1244,6 +1244,19 @@ ui_EndList(ui_interface* Interface) ui_EndRow(Interface); } +internal void +ui_BeginMousePopup(ui_interface* Interface, rect2 Bounds, ui_layout_direction FillDir, gs_string Text) +{ + rect2 FollowMouseBounds = Rect2Translate(Bounds, Interface->Mouse.Pos); + ui_widget* Layout = ui_PushOverlayLayout(Interface, FollowMouseBounds, FillDir, Text); + ui_WidgetSetFlag(Layout, UIWidgetFlag_DrawBackground); +} + +internal void +ui_EndMousePopup(ui_interface* Interface) +{ + ui_PopLayout(Interface); +} #define INTERFACE_H #endif // INTERFACE_H \ No newline at end of file