diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index 8c3b351..18f48bb 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -11,79 +11,6 @@ SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPan GlobalPanelDefs[NewPanelDefinitionIndex].Init(Panel); } - -internal void -DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBounds, interface_config Interface, mouse_state Mouse) -{ - PushRenderQuad2D(RenderBuffer, FooterBounds.Min, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f}); - PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4); - - v2 PanelSelectButtonMin = FooterBounds.Min + v2{30, 1}; - v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23}; - - if (Panel->PanelSelectionMenuOpen) - { - v2 ButtonDimension = v2{100, 25}; - v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterBounds.Max.y}; - - v2 MenuMin = ButtonMin; - v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)}; - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) - && !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax)) - { - Panel->PanelSelectionMenuOpen = false; - } - - - for (s32 i = 0; i < GlobalPanelDefsCount; i++) - { - panel_definition Def = GlobalPanelDefs[i]; - string DefName = MakeString(Def.PanelName, Def.PanelNameLength); - button_result DefinitionButton = EvaluateButton(RenderBuffer, - ButtonMin, ButtonMin + ButtonDimension, - DefName, Interface, Mouse); - if (DefinitionButton.Pressed) - { - SetPanelDefinition(Panel, i); - Panel->PanelSelectionMenuOpen = false; - } - - ButtonMin.y += ButtonDimension.y; - } - } - - button_result ButtonResult = EvaluateButton(RenderBuffer, - PanelSelectButtonMin, - PanelSelectButtonMax, - MakeStringLiteral("Select"), Interface, Mouse); - if (ButtonResult.Pressed) - { - Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen; - } - -} - -internal void -RenderPanel(panel* Panel, rect PanelBounds, rect WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) -{ - Assert(Panel->PanelDefinitionIndex >= 0); - - rect FooterBounds = rect{ - PanelBounds.Min, - v2{PanelBounds.Max.x, PanelBounds.Min.y + 25}, - }; - rect PanelViewBounds = rect{ - v2{PanelBounds.Min.x, FooterBounds.Max.y}, - PanelBounds.Max, - }; - - panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex]; - Definition.Render(*Panel, PanelViewBounds, RenderBuffer, State, Context, Mouse); - - PushRenderOrthographic(RenderBuffer, WindowBounds.Min.x, WindowBounds.Min.y, WindowBounds.Max.x, WindowBounds.Max.y); - DrawPanelFooter(Panel, RenderBuffer, FooterBounds, State->Interface, Mouse); -} - internal v4 MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, rect WindowBounds) { @@ -297,42 +224,46 @@ HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_ { DEBUG_TRACK_FUNCTION; - input_command_registry ActiveCommands = {}; - if (State->Modes.ActiveModesCount > 0) + b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); + if (!PanelSystemHandledInput) { - ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; - } - else - { - panel_and_bounds PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); - if (!PanelWithMouseOverIt.Panel) { return; } - - panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex]; - if (!PanelDefinition.InputCommands) { return; } - - ActiveCommands.Commands = PanelDefinition.InputCommands; - ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]); - ActiveCommands.Used = ActiveCommands.Size; - } - - for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) - { - input_entry Event = InputQueue.Entries[EventIdx]; - - // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege - // Down and Up over Held. In other words, we don't want to call a Held command on the - // frame when the button was released, even if the command is registered to both events - if (KeyTransitionedDown(Event)) + input_command_registry ActiveCommands = {}; + if (State->Modes.ActiveModesCount > 0) { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue); + ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; } - else if (KeyTransitionedUp(Event)) + else { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); + panel_and_bounds PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); + if (!PanelWithMouseOverIt.Panel) { return; } + + panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex]; + if (!PanelDefinition.InputCommands) { return; } + + ActiveCommands.Commands = PanelDefinition.InputCommands; + ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]); + ActiveCommands.Used = ActiveCommands.Size; } - else if (KeyHeldDown(Event)) + + for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue); + input_entry Event = InputQueue.Entries[EventIdx]; + + // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege + // Down and Up over Held. In other words, we don't want to call a Held command on the + // frame when the button was released, even if the command is registered to both events + if (KeyTransitionedDown(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue); + } + else if (KeyTransitionedUp(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); + } + else if (KeyHeldDown(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue); + } } } @@ -394,152 +325,6 @@ CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena) return Result; } -#define PANEL_EDGE_CLICK_MAX_DISTANCE 6 - -internal void -HandleMousePanelInteractionOrRecurse(panel* Panel, rect PanelBounds, panel_system* PanelLayout, mouse_state Mouse) -{ - // TODO(Peter): Need a way to calculate this button's position more systemically - if (Panel->SplitDirection == PanelSplit_NoSplit - && PointIsInRange(Mouse.DownPos, PanelBounds.Min, PanelBounds.Min + v2{25, 25})) - { - r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); - r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); - - if (XDistance > YDistance) - { - r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Width(PanelBounds); - SplitPanelVertically(Panel, XPercent, PanelBounds, PanelLayout); - } - else - { - r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Height(PanelBounds); - SplitPanelHorizontally(Panel, YPercent, PanelBounds, PanelLayout); - } - } - else if (Panel->SplitDirection == PanelSplit_Horizontal) - { - r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent); - r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY); - if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) - { - r32 NewSplitY = Mouse.Pos.y; - if (NewSplitY <= PanelBounds.Min.y) - { - ConsolidatePanelsKeepOne(Panel, Panel->Top, PanelLayout); - } - else if (NewSplitY >= PanelBounds.Max.y) - { - ConsolidatePanelsKeepOne(Panel, Panel->Bottom, PanelLayout); - } - else - { - Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Height(PanelBounds); - } - } - else - { - rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); - rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); - HandleMousePanelInteractionOrRecurse(&Panel->Bottom->Panel, BottomPanelBounds, PanelLayout, Mouse); - HandleMousePanelInteractionOrRecurse(&Panel->Top->Panel, TopPanelBounds, PanelLayout, Mouse); - } - } - else if (Panel->SplitDirection == PanelSplit_Vertical) - { - r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent); - r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX); - if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) - { - r32 NewSplitX = Mouse.Pos.x; - if (NewSplitX <= PanelBounds.Min.x) - { - ConsolidatePanelsKeepOne(Panel, Panel->Right, PanelLayout); - } - else if (NewSplitX >= PanelBounds.Max.x) - { - ConsolidatePanelsKeepOne(Panel, Panel->Left, PanelLayout); - } - else - { - Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Width(PanelBounds); - } - } - else - { - rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); - rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); - HandleMousePanelInteractionOrRecurse(&Panel->Left->Panel, LeftPanelBounds, PanelLayout, Mouse); - HandleMousePanelInteractionOrRecurse(&Panel->Right->Panel, RightPanelBounds, PanelLayout, Mouse); - } - } -} - -internal void -HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds,mouse_state Mouse) -{ - if (MouseButtonTransitionedUp(Mouse.LeftButtonState)) - { - Assert(PanelSystem->PanelsUsed > 0); - panel* FirstPanel = &PanelSystem->Panels[0].Panel; - HandleMousePanelInteractionOrRecurse(FirstPanel, WindowBounds, PanelSystem, Mouse); - } -} - -internal void -DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state Mouse, render_command_buffer* RenderBuffer) -{ - r32 MouseLeftEdgeDistance = GSAbs(Mouse.Pos.x - PanelMin.x); - r32 MouseRightEdgeDistance = GSAbs(Mouse.Pos.x - PanelMax.x); - r32 MouseTopEdgeDistance = GSAbs(Mouse.Pos.y - PanelMax.y); - r32 MouseBottomEdgeDistance = GSAbs(Mouse.Pos.y - PanelMin.y); - - PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); - v4 HighlightColor = v4{.3f, .3f, .3f, 1.f}; - r32 HighlightThickness = 1; - if (MouseLeftEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) - { - v2 LeftEdgeMin = PanelMin; - v2 LeftEdgeMax = v2{PanelMin.x + HighlightThickness, PanelMax.y}; - PushRenderQuad2D(RenderBuffer, LeftEdgeMin, LeftEdgeMax, HighlightColor); - } - else if (MouseRightEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) - { - v2 RightEdgeMin = v2{PanelMax.x - HighlightThickness, PanelMin.y}; - v2 RightEdgeMax = PanelMax; - PushRenderQuad2D(RenderBuffer, RightEdgeMin, RightEdgeMax, HighlightColor); - } - else if (MouseTopEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) - { - v2 TopEdgeMin = v2{PanelMin.x, PanelMax.y - HighlightThickness}; - v2 TopEdgeMax = PanelMax; - PushRenderQuad2D(RenderBuffer, TopEdgeMin, TopEdgeMax, HighlightColor); - } - else if (MouseBottomEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) - { - v2 BottomEdgeMin = PanelMin; - v2 BottomEdgeMax = v2{PanelMax.x, PanelMin.y + HighlightThickness}; - PushRenderQuad2D(RenderBuffer, BottomEdgeMin, BottomEdgeMax, HighlightColor); - } -} - -internal void -DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mouse_state Mouse, app_state* State, context Context) -{ - for (u32 i = 0; i < PanelLayout.PanelsCount; i++) - { - panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; - panel* Panel = PanelWithLayout.Panel; - rect PanelBounds = PanelWithLayout.Bounds; - - RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, Mouse); - v4 BorderColor = v4{0, 0, 0, 1}; - - PushRenderOrthographic(RenderBuffer, State->WindowBounds.Min.x, State->WindowBounds.Min.y, State->WindowBounds.Max.x, State->WindowBounds.Max.y); - DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer); - } -} - UPDATE_AND_RENDER(UpdateAndRender) { DEBUG_TRACK_FUNCTION; @@ -632,8 +417,6 @@ UPDATE_AND_RENDER(UpdateAndRender) PushRenderOrthographic(RenderBuffer, 0, 0, Width(State->WindowBounds), Height(State->WindowBounds)); PushRenderClearScreen(RenderBuffer); - HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse); - panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, &State->Transient); DrawAllPanels(PanelsToRender, RenderBuffer, Mouse, State, Context); diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index f93d7ea..3c60263 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -198,8 +198,6 @@ TestPatternThree(assembly* Assembly, r32 Time) #include "foldhaus_text_entry.cpp" #include "foldhaus_search_lister.cpp" -#include "foldhaus_interface.cpp" - #define PANEL_INIT_PROC(name) void name(panel* Panel) typedef PANEL_INIT_PROC(panel_init_proc); @@ -216,3 +214,5 @@ typedef PANEL_RENDER_PROC(panel_render_proc); #include "panels/foldhaus_panel_hierarchy.h" #include "generated/foldhaus_panels_generated.h" + +#include "foldhaus_interface.cpp" diff --git a/src/foldhaus_interface.cpp b/src/foldhaus_interface.cpp index 9c22441..d1b28f2 100644 --- a/src/foldhaus_interface.cpp +++ b/src/foldhaus_interface.cpp @@ -126,3 +126,369 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenUniverseView) OpState->DisplayOffset = v2{0, 0}; OpState->Zoom = 1.0f; } + +//////////////////////////////////////// +// +// Panels +// +/////////////////////////////////////// + +// +// Drag Panel Border Operation Mode + +OPERATION_STATE_DEF(drag_panel_border_operation_state) +{ + panel* Panel; + + // NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying, + // it stores the value calculated when the operation mode is kicked off. + rect InitialPanelBounds; + panel_split_direction PanelEdgeDirection; +}; + +OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder) +{ + drag_panel_border_operation_state* OpState = (drag_panel_border_operation_state*)Operation.OpStateMemory; + rect PanelBounds = OpState->InitialPanelBounds; + v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f}; + + v2 EdgePreviewMin = {}; + v2 EdgePreviewMax = {}; + if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) + { + EdgePreviewMin = v2{PanelBounds.Min.x, Mouse.Pos.y}; + EdgePreviewMax = v2{PanelBounds.Max.x, Mouse.Pos.y + 1}; + } + else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) + { + EdgePreviewMin = v2{Mouse.Pos.x, PanelBounds.Min.y}; + EdgePreviewMax = v2{Mouse.Pos.x + 1, PanelBounds.Max.y}; + } + + PushRenderQuad2D(RenderBuffer, EdgePreviewMin, EdgePreviewMax, EdgePreviewColor); +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) +{ + drag_panel_border_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_panel_border_operation_state); + panel* Panel = OpState->Panel; + rect PanelBounds = OpState->InitialPanelBounds; + + if (Panel->SplitDirection == PanelSplit_Horizontal) + { + r32 NewSplitY = Mouse.Pos.y; + if (NewSplitY <= PanelBounds.Min.y) + { + ConsolidatePanelsKeepOne(Panel, Panel->Top, &State->PanelSystem); + } + else if (NewSplitY >= PanelBounds.Max.y) + { + ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem); + } + else + { + Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Height(PanelBounds); + } + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + r32 NewSplitX = Mouse.Pos.x; + if (NewSplitX <= PanelBounds.Min.x) + { + ConsolidatePanelsKeepOne(Panel, Panel->Right, &State->PanelSystem); + } + else if (NewSplitX >= PanelBounds.Max.x) + { + ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem); + } + else + { + Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Width(PanelBounds); + } + } + + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragPanelBorderCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragPanelBorderOperation }, +}; + +internal void +BeginDragPanelBorder(panel* Panel, rect PanelBounds, panel_split_direction PanelEdgeDirection, mouse_state Mouse, app_state* State) +{ + operation_mode* DragPanelBorder = ActivateOperationModeWithCommands(&State->Modes, DragPanelBorderCommands, UpdateAndRenderDragPanelBorder); + drag_panel_border_operation_state* OpState = CreateOperationState(DragPanelBorder, &State->Modes, drag_panel_border_operation_state); + OpState->Panel = Panel; + OpState->InitialPanelBounds = PanelBounds; + OpState->PanelEdgeDirection = PanelEdgeDirection; +} + +// ---------------- + +// +// Drag To Split Panel Operation + + +OPERATION_STATE_DEF(split_panel_operation_state) +{ + panel* Panel; + + // NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying, + // it stores the value calculated when the operation mode is kicked off. + rect InitialPanelBounds; +}; + +OPERATION_RENDER_PROC(UpdateAndRenderSplitPanel) +{ + split_panel_operation_state* OpState = (split_panel_operation_state*)Operation.OpStateMemory; + rect PanelBounds = OpState->InitialPanelBounds; + v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f}; + + r32 MouseDeltaX = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); + r32 MouseDeltaY = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); + + v2 EdgePreviewMin = {}; + v2 EdgePreviewMax = {}; + if (MouseDeltaY > MouseDeltaX) // Horizontal Split + { + EdgePreviewMin = v2{PanelBounds.Min.x, Mouse.Pos.y}; + EdgePreviewMax = v2{PanelBounds.Max.x, Mouse.Pos.y + 1}; + } + else // Vertical Split + { + EdgePreviewMin = v2{Mouse.Pos.x, PanelBounds.Min.y}; + EdgePreviewMax = v2{Mouse.Pos.x + 1, PanelBounds.Max.y}; + } + + PushRenderQuad2D(RenderBuffer, EdgePreviewMin, EdgePreviewMax, EdgePreviewColor); +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation) +{ + split_panel_operation_state* OpState = GetCurrentOperationState(State->Modes, split_panel_operation_state); + panel* Panel = OpState->Panel; + rect PanelBounds = OpState->InitialPanelBounds; + + r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); + r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); + + if (XDistance > YDistance) + { + r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Width(PanelBounds); + SplitPanelVertically(Panel, XPercent, PanelBounds, &State->PanelSystem); + } + else + { + r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Height(PanelBounds); + SplitPanelHorizontally(Panel, YPercent, PanelBounds, &State->PanelSystem); + } + + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command SplitPanelCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndSplitPanelOperation }, +}; + +internal void +BeginSplitPanelOperation(panel* Panel, rect PanelBounds, mouse_state Mouse, app_state* State) +{ + operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel); + split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state); + OpState->Panel = Panel; + OpState->InitialPanelBounds = PanelBounds; +} + + +// ---------------- + +#define PANEL_EDGE_CLICK_MAX_DISTANCE 6 + +internal b32 +HandleMouseDownPanelInteractionOrRecurse(panel* Panel, rect PanelBounds, mouse_state Mouse, app_state* State) +{ + b32 HandledMouseInput = false; + + if (Panel->SplitDirection == PanelSplit_NoSplit + && PointIsInRange(Mouse.DownPos, PanelBounds.Min, PanelBounds.Min + v2{25, 25})) + { + BeginSplitPanelOperation(Panel, PanelBounds, Mouse, State); + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent); + r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY); + if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + BeginDragPanelBorder(Panel, PanelBounds, PanelSplit_Horizontal, Mouse, State); + HandledMouseInput = true; + } + else + { + rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + HandleMouseDownPanelInteractionOrRecurse(&Panel->Bottom->Panel, BottomPanelBounds, Mouse, State); + HandleMouseDownPanelInteractionOrRecurse(&Panel->Top->Panel, TopPanelBounds, Mouse, State); + } + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent); + r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX); + if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + BeginDragPanelBorder(Panel, PanelBounds, PanelSplit_Vertical, Mouse, State); + HandledMouseInput = true; + } + else + { + rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + HandleMouseDownPanelInteractionOrRecurse(&Panel->Left->Panel, LeftPanelBounds, Mouse, State); + HandleMouseDownPanelInteractionOrRecurse(&Panel->Right->Panel, RightPanelBounds, Mouse, State); + } + } + + return HandledMouseInput; +} + +internal b32 +HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds, mouse_state Mouse, app_state* State) +{ + b32 HandledMouseInput = false; + + if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) + { + panel* FirstPanel = &PanelSystem->Panels[0].Panel; + HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, WindowBounds, Mouse, State); + } + + return HandledMouseInput; +} + +internal void +DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state Mouse, render_command_buffer* RenderBuffer) +{ + r32 MouseLeftEdgeDistance = GSAbs(Mouse.Pos.x - PanelMin.x); + r32 MouseRightEdgeDistance = GSAbs(Mouse.Pos.x - PanelMax.x); + r32 MouseTopEdgeDistance = GSAbs(Mouse.Pos.y - PanelMax.y); + r32 MouseBottomEdgeDistance = GSAbs(Mouse.Pos.y - PanelMin.y); + + PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); + v4 HighlightColor = v4{.3f, .3f, .3f, 1.f}; + r32 HighlightThickness = 1; + if (MouseLeftEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 LeftEdgeMin = PanelMin; + v2 LeftEdgeMax = v2{PanelMin.x + HighlightThickness, PanelMax.y}; + PushRenderQuad2D(RenderBuffer, LeftEdgeMin, LeftEdgeMax, HighlightColor); + } + else if (MouseRightEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 RightEdgeMin = v2{PanelMax.x - HighlightThickness, PanelMin.y}; + v2 RightEdgeMax = PanelMax; + PushRenderQuad2D(RenderBuffer, RightEdgeMin, RightEdgeMax, HighlightColor); + } + else if (MouseTopEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 TopEdgeMin = v2{PanelMin.x, PanelMax.y - HighlightThickness}; + v2 TopEdgeMax = PanelMax; + PushRenderQuad2D(RenderBuffer, TopEdgeMin, TopEdgeMax, HighlightColor); + } + else if (MouseBottomEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 BottomEdgeMin = PanelMin; + v2 BottomEdgeMax = v2{PanelMax.x, PanelMin.y + HighlightThickness}; + PushRenderQuad2D(RenderBuffer, BottomEdgeMin, BottomEdgeMax, HighlightColor); + } +} + +internal void +DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBounds, interface_config Interface, mouse_state Mouse) +{ + PushRenderQuad2D(RenderBuffer, FooterBounds.Min, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f}); + PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4); + + v2 PanelSelectButtonMin = FooterBounds.Min + v2{30, 1}; + v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23}; + + if (Panel->PanelSelectionMenuOpen) + { + v2 ButtonDimension = v2{100, 25}; + v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterBounds.Max.y}; + + v2 MenuMin = ButtonMin; + v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)}; + if (MouseButtonTransitionedDown(Mouse.LeftButtonState) + && !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax)) + { + Panel->PanelSelectionMenuOpen = false; + } + + + for (s32 i = 0; i < GlobalPanelDefsCount; i++) + { + panel_definition Def = GlobalPanelDefs[i]; + string DefName = MakeString(Def.PanelName, Def.PanelNameLength); + button_result DefinitionButton = EvaluateButton(RenderBuffer, + ButtonMin, ButtonMin + ButtonDimension, + DefName, Interface, Mouse); + if (DefinitionButton.Pressed) + { + SetPanelDefinition(Panel, i); + Panel->PanelSelectionMenuOpen = false; + } + + ButtonMin.y += ButtonDimension.y; + } + } + + button_result ButtonResult = EvaluateButton(RenderBuffer, + PanelSelectButtonMin, + PanelSelectButtonMax, + MakeStringLiteral("Select"), Interface, Mouse); + if (ButtonResult.Pressed) + { + Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen; + } + +} + +internal void +RenderPanel(panel* Panel, rect PanelBounds, rect WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +{ + Assert(Panel->PanelDefinitionIndex >= 0); + + rect FooterBounds = rect{ + PanelBounds.Min, + v2{PanelBounds.Max.x, PanelBounds.Min.y + 25}, + }; + rect PanelViewBounds = rect{ + v2{PanelBounds.Min.x, FooterBounds.Max.y}, + PanelBounds.Max, + }; + + panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex]; + Definition.Render(*Panel, PanelViewBounds, RenderBuffer, State, Context, Mouse); + + PushRenderOrthographic(RenderBuffer, WindowBounds.Min.x, WindowBounds.Min.y, WindowBounds.Max.x, WindowBounds.Max.y); + DrawPanelFooter(Panel, RenderBuffer, FooterBounds, State->Interface, Mouse); +} + +internal void +DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mouse_state Mouse, app_state* State, context Context) +{ + for (u32 i = 0; i < PanelLayout.PanelsCount; i++) + { + panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; + panel* Panel = PanelWithLayout.Panel; + rect PanelBounds = PanelWithLayout.Bounds; + + RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, Mouse); + v4 BorderColor = v4{0, 0, 0, 1}; + + PushRenderOrthographic(RenderBuffer, State->WindowBounds.Min.x, State->WindowBounds.Min.y, State->WindowBounds.Max.x, State->WindowBounds.Max.y); + DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer); + } +} diff --git a/src/foldhaus_operation_mode.h b/src/foldhaus_operation_mode.h index 19473a5..6c9b490 100644 --- a/src/foldhaus_operation_mode.h +++ b/src/foldhaus_operation_mode.h @@ -72,7 +72,7 @@ DeactivateCurrentOperationMode (operation_mode_system* System) (stateType*)CreateOperationState_(mode, modeSystem, sizeof(stateType)) #define GetCurrentOperationState(modeSystem, stateType) \ -(stateType*)State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].OpStateMemory; +(stateType*)(modeSystem).ActiveModes[(modeSystem).ActiveModesCount - 1].OpStateMemory; internal u8*