Implemented a list view, which included upgrading rendering strings to accept clipping masks
This commit is contained in:
parent
296472a588
commit
118b734d6c
|
@ -89,7 +89,7 @@ Editor_Update(app_state* State, context* Context, input_queue InputQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
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,
|
render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(RenderBuffer,
|
||||||
Widget.String.Length,
|
Widget.String.Length,
|
||||||
|
@ -106,12 +106,12 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe
|
||||||
{
|
{
|
||||||
case Align_Left:
|
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;
|
}break;
|
||||||
|
|
||||||
case Align_Right:
|
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;
|
}break;
|
||||||
|
|
||||||
InvalidDefaultCase;
|
InvalidDefaultCase;
|
||||||
|
@ -121,62 +121,109 @@ Editor_DrawWidgetString(app_state* State, context* Context, render_command_buffe
|
||||||
internal void
|
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)
|
||||||
{
|
{
|
||||||
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground))
|
rect2 WidgetParentUnion = Widget.Bounds;
|
||||||
|
if (Widget.Parent)
|
||||||
{
|
{
|
||||||
v4 Color = State->Interface.Style.ButtonColor_Inactive;
|
WidgetParentUnion = Rect2Union(Widget.Bounds, Widget.Parent->Bounds);
|
||||||
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 (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0)
|
if (!Widget.Parent || (Rect2Area(WidgetParentUnion) > 0))
|
||||||
{
|
{
|
||||||
v4 Color = State->Interface.Style.TextColor;
|
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawBackground))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
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)
|
if (ui_WidgetIsFlagSet(Widget, UIWidgetFlag_DrawString) && Widget.String.Length > 0)
|
||||||
{
|
{
|
||||||
// TODO(pjs): Mask this text by the horizontal fill
|
v4 Color = State->Interface.Style.TextColor;
|
||||||
// TODO(pjs): add this color to the style
|
Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, WidgetParentUnion, Color);
|
||||||
v4 TextColor = BlackV4;
|
}
|
||||||
Editor_DrawWidgetString(State, Context, RenderBuffer, Widget, TextColor);
|
|
||||||
|
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)
|
if (Widget.ChildrenRoot)
|
||||||
|
@ -207,21 +254,29 @@ TestRender(app_state* State, context* Context, render_command_buffer* RenderBuff
|
||||||
ui_PushLayout(&State->Interface, A);
|
ui_PushLayout(&State->Interface, A);
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
ui_column_spec ColumnRules[] = {
|
ui_Label(&State->Interface, MakeString("Spacer"));
|
||||||
{ UIColumnSize_Fixed, 128 },
|
ui_Label(&State->Interface, MakeString("Spacer"));
|
||||||
{ UIColumnSize_Fill, 0 },
|
ui_Label(&State->Interface, MakeString("Spacer"));
|
||||||
{ UIColumnSize_Percent, .5f }
|
ui_Label(&State->Interface, MakeString("Spacer"));
|
||||||
};
|
ui_Label(&State->Interface, MakeString("Spacer"));
|
||||||
ui_BeginRow(&State->Interface, 3, ColumnRules);
|
|
||||||
|
|
||||||
|
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_Button(&State->Interface, MakeString("B"));
|
||||||
|
ui_Button(&State->Interface, MakeString("B"));
|
||||||
|
ui_Button(&State->Interface, MakeString("B"));
|
||||||
|
|
||||||
}
|
}
|
||||||
ui_EndRow(&State->Interface);
|
ui_EndList(&State->Interface);
|
||||||
ui_Button(&State->Interface, MakeString("B"));
|
//ui_Button(&State->Interface, MakeString("B"));
|
||||||
ui_Button(&State->Interface, MakeString("C"));
|
//ui_Button(&State->Interface, MakeString("C"));
|
||||||
|
//TestSlider_Value = ui_RangeSlider(&State->Interface, MakeString("TestSlider"), TestSlider_Value, TestSlider_Min, TestSlider_Max);
|
||||||
#elif 0
|
#elif 0
|
||||||
ui_PushLayout(&State->Interface, MakeString("Outer"));
|
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);
|
PushRenderOrthographic(RenderBuffer, State->WindowBounds);
|
||||||
PushRenderClearScreen(RenderBuffer);
|
PushRenderClearScreen(RenderBuffer);
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
TestRender(State, Context, RenderBuffer);
|
TestRender(State, Context, RenderBuffer);
|
||||||
#else
|
#else
|
||||||
ui_InterfaceReset(&State->Interface);
|
ui_InterfaceReset(&State->Interface);
|
||||||
|
|
|
@ -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
|
// NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could
|
||||||
// be removed, or used for something else
|
// 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")))
|
if (ui_Button(&State->Interface, MakeString("Resume Recording")))
|
||||||
{
|
{
|
||||||
|
|
|
@ -589,6 +589,21 @@ PushRenderQuad2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color)
|
||||||
PushQuad2DOnBatch(&Batch, Min, Max, 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
|
internal void
|
||||||
PushRenderQuad2D(render_command_buffer* Buffer, v2 P0, v2 P1, v2 P2, v2 P3, v4 Color)
|
PushRenderQuad2D(render_command_buffer* Buffer, v2 P0, v2 P1, v2 P2, v2 P3, v4 Color)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,22 +13,68 @@ enum gs_string_alignment
|
||||||
};
|
};
|
||||||
|
|
||||||
internal void
|
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 AlignedMinX = (s32)(MinX);
|
||||||
s32 AlignedMinY = (s32)(MinY);
|
s32 AlignedMinY = (s32)(MinY);
|
||||||
s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width);
|
s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width);
|
||||||
s32 AlignedMaxY = AlignedMinY + (CodepointInfo.Height);
|
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,
|
PushQuad2DOnBatch(BatchConstructor,
|
||||||
v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY},
|
v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY},
|
||||||
v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY},
|
v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY},
|
||||||
CodepointInfo.UVMin, CodepointInfo.UVMax,
|
CodepointInfo.UVMin, CodepointInfo.UVMax,
|
||||||
Color);
|
Color);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
internal v2
|
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);
|
s32 GlyphDataIndex = GetIndexForCodepoint(Font, C);
|
||||||
codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex];
|
codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex];
|
||||||
|
@ -36,7 +82,7 @@ DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char
|
||||||
// NOTE(Peter):
|
// NOTE(Peter):
|
||||||
r32 MinX = Position.x + CodepointInfo.XOffset;
|
r32 MinX = Position.x + CodepointInfo.XOffset;
|
||||||
r32 MinY = Position.y + CodepointInfo.YOffset;
|
r32 MinY = Position.y + CodepointInfo.YOffset;
|
||||||
DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, Color);
|
DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, ClippingBox, Color);
|
||||||
|
|
||||||
// NOTE(Peter):
|
// NOTE(Peter):
|
||||||
v2 PointAfterCharacter = v2{Position.x + CodepointInfo.Width, Position.y};
|
v2 PointAfterCharacter = v2{Position.x + CodepointInfo.Width, Position.y};
|
||||||
|
@ -44,7 +90,7 @@ DrawCharacterLeftAligned (render_quad_batch_constructor* BatchConstructor, char
|
||||||
}
|
}
|
||||||
|
|
||||||
internal v2
|
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);
|
s32 GlyphDataIndex = GetIndexForCodepoint(Font, C);
|
||||||
codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex];
|
codepoint_bitmap CodepointInfo = Font.CodepointValues[GlyphDataIndex];
|
||||||
|
@ -52,7 +98,7 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char
|
||||||
// NOTE(Peter):
|
// NOTE(Peter):
|
||||||
r32 MinX = Position.x - (CodepointInfo.XOffset + CodepointInfo.Width);
|
r32 MinX = Position.x - (CodepointInfo.XOffset + CodepointInfo.Width);
|
||||||
r32 MinY = Position.y + CodepointInfo.YOffset + CodepointInfo.YOffset;
|
r32 MinY = Position.y + CodepointInfo.YOffset + CodepointInfo.YOffset;
|
||||||
DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, Color);
|
DrawCharacter_(BatchConstructor, MinX, MinY, CodepointInfo, ClippingBox, Color);
|
||||||
|
|
||||||
// NOTE(Peter):
|
// NOTE(Peter):
|
||||||
v2 PointAfterCharacter = v2{Position.x-(CodepointInfo.Width + CodepointInfo.XOffset), Position.y};
|
v2 PointAfterCharacter = v2{Position.x-(CodepointInfo.Width + CodepointInfo.XOffset), Position.y};
|
||||||
|
@ -60,13 +106,13 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char
|
||||||
}
|
}
|
||||||
|
|
||||||
internal v2
|
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;
|
v2 RegisterPosition = InitialRegisterPosition;
|
||||||
char* C = gs_string;
|
char* C = gs_string;
|
||||||
for (s32 i = 0; i < Length; i++)
|
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;
|
RegisterPosition.x = PositionAfterCharacter.x;
|
||||||
C++;
|
C++;
|
||||||
}
|
}
|
||||||
|
@ -74,13 +120,13 @@ DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Leng
|
||||||
}
|
}
|
||||||
|
|
||||||
internal v2
|
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;
|
v2 RegisterPosition = InitialRegisterPosition;
|
||||||
char* C = gs_string + Length - 1;
|
char* C = gs_string + Length - 1;
|
||||||
for (s32 i = Length - 1; i >= 0; i--)
|
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;
|
RegisterPosition.x = PositionAfterCharacter.x;
|
||||||
C--;
|
C--;
|
||||||
}
|
}
|
||||||
|
@ -101,14 +147,22 @@ DrawString(render_command_buffer* RenderBuffer, gs_string String, bitmap_font* F
|
||||||
Font->BitmapBytesPerPixel,
|
Font->BitmapBytesPerPixel,
|
||||||
Font->BitmapStride);
|
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;
|
v2 RegisterPosition = Position;
|
||||||
if (Alignment == Align_Left)
|
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)
|
else if (Alignment == Align_Right)
|
||||||
{
|
{
|
||||||
RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, Color);
|
RegisterPosition = DrawStringRightAligned(&BatchConstructor, StringExpand(String), RegisterPosition, Font, InfiniteClipBox, Color);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -128,6 +182,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col
|
||||||
PushQuad2DOnBatch(BatchConstructor, Min, Max, Color);
|
PushQuad2DOnBatch(BatchConstructor, Min, Max, Color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
internal v2
|
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)
|
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;
|
LowerRight.x = RegisterPosition.x;
|
||||||
return LowerRight;
|
return LowerRight;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
enum ui_widget_flag
|
enum ui_widget_flag
|
||||||
{
|
{
|
||||||
|
UIWidgetFlag_ExpandsToFitChildren,
|
||||||
UIWidgetFlag_DrawBackground,
|
UIWidgetFlag_DrawBackground,
|
||||||
UIWidgetFlag_DrawString,
|
UIWidgetFlag_DrawString,
|
||||||
UIWidgetFlag_DrawOutline,
|
UIWidgetFlag_DrawOutline,
|
||||||
UIWidgetFlag_Clickable,
|
UIWidgetFlag_Clickable,
|
||||||
UIWidgetFlag_DrawHorizontalFill,
|
UIWidgetFlag_DrawHorizontalFill,
|
||||||
|
UIWidgetFlag_DrawVerticalFill,
|
||||||
|
UIWidgetFlag_DrawFillReversed,
|
||||||
|
UIWidgetFlag_DrawFillAsHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ui_widget_id
|
struct ui_widget_id
|
||||||
|
@ -221,7 +281,7 @@ struct ui_widget
|
||||||
ui_widget* Next;
|
ui_widget* Next;
|
||||||
|
|
||||||
// Slider
|
// Slider
|
||||||
r32 HorizontalFillPercent;
|
r32 FillPercent;
|
||||||
|
|
||||||
// Layout
|
// Layout
|
||||||
ui_widget* Parent;
|
ui_widget* Parent;
|
||||||
|
@ -279,6 +339,9 @@ struct ui_widget_retained_state
|
||||||
bool Value;
|
bool Value;
|
||||||
r32 InitialValueR32;
|
r32 InitialValueR32;
|
||||||
u32 FramesSinceAccess;
|
u32 FramesSinceAccess;
|
||||||
|
|
||||||
|
// For use in layouts that allow you to scroll / pan
|
||||||
|
v2 ChildrenDrawOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ui_interface
|
struct ui_interface
|
||||||
|
@ -381,6 +444,17 @@ ui_CreateRetainedState(ui_interface* Interface, ui_widget* Widget)
|
||||||
return Result;
|
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*
|
internal ui_widget*
|
||||||
ui_CreateWidget(ui_interface* Interface, gs_string String)
|
ui_CreateWidget(ui_interface* Interface, gs_string String)
|
||||||
{
|
{
|
||||||
|
@ -405,6 +479,7 @@ ui_CreateWidget(ui_interface* Interface, gs_string String)
|
||||||
Result->ChildrenRoot = 0;
|
Result->ChildrenRoot = 0;
|
||||||
Result->ChildrenHead = 0;
|
Result->ChildrenHead = 0;
|
||||||
Result->Flags = 0;
|
Result->Flags = 0;
|
||||||
|
ui_WidgetSetFlag(Result, UIWidgetFlag_ExpandsToFitChildren);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
@ -424,7 +499,7 @@ ui_MouseClickedRect(ui_interface Interface, rect2 Rect)
|
||||||
// Layout
|
// Layout
|
||||||
|
|
||||||
static rect2
|
static rect2
|
||||||
ui_ReserveBounds(ui_widget* Widget, bool Inset)
|
ui_ReserveBounds(ui_interface* Interface, ui_widget* Widget, bool Inset)
|
||||||
{
|
{
|
||||||
Assert(Widget->ColumnsCount > 0);
|
Assert(Widget->ColumnsCount > 0);
|
||||||
rect2 Bounds = {0};
|
rect2 Bounds = {0};
|
||||||
|
@ -444,6 +519,15 @@ ui_ReserveBounds(ui_widget* Widget, bool Inset)
|
||||||
Bounds.Max.y -= Widget->Margin.y;
|
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;
|
return Bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,7 +669,7 @@ ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true)
|
||||||
ui_layout_direction Direction = LayoutDirection_TopDown;
|
ui_layout_direction Direction = LayoutDirection_TopDown;
|
||||||
if (Interface->ActiveLayout)
|
if (Interface->ActiveLayout)
|
||||||
{
|
{
|
||||||
Bounds = ui_ReserveBounds(Interface->ActiveLayout, Inset);
|
Bounds = ui_ReserveBounds(Interface, Interface->ActiveLayout, Inset);
|
||||||
Direction = Interface->ActiveLayout->FillDirection;
|
Direction = Interface->ActiveLayout->FillDirection;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -609,6 +693,8 @@ ui_PushLayout(ui_interface* Interface, gs_string Name, bool Inset = true)
|
||||||
internal void
|
internal void
|
||||||
ui_ExpandToFitChildren(ui_widget* Parent)
|
ui_ExpandToFitChildren(ui_widget* Parent)
|
||||||
{
|
{
|
||||||
|
if (!ui_WidgetIsFlagSet(*Parent, UIWidgetFlag_ExpandsToFitChildren)) { return; }
|
||||||
|
|
||||||
v2 Extents = { Parent->Bounds.Max.y, Parent->Bounds.Min.y };
|
v2 Extents = { Parent->Bounds.Max.y, Parent->Bounds.Min.y };
|
||||||
for (ui_widget* Child = Parent->ChildrenRoot; Child != 0; Child = Child->Next)
|
for (ui_widget* Child = Parent->ChildrenRoot; Child != 0; Child = Child->Next)
|
||||||
{
|
{
|
||||||
|
@ -620,12 +706,12 @@ ui_ExpandToFitChildren(ui_widget* Parent)
|
||||||
{
|
{
|
||||||
case LayoutDirection_BottomUp:
|
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;
|
}break;
|
||||||
|
|
||||||
case LayoutDirection_TopDown:
|
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;
|
}break;
|
||||||
|
|
||||||
InvalidDefaultCase;
|
InvalidDefaultCase;
|
||||||
|
@ -651,12 +737,13 @@ ui_PopLayout(ui_interface* Interface)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static ui_widget*
|
||||||
ui_BeginRow(ui_interface* Interface, u32 ColumnsMax)
|
ui_BeginRow(ui_interface* Interface, u32 ColumnsMax)
|
||||||
{
|
{
|
||||||
ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false);
|
ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false);
|
||||||
ui_WidgetCreateColumns(Layout, ColumnsMax, Interface);
|
ui_WidgetCreateColumns(Layout, ColumnsMax, Interface);
|
||||||
ui_WidgetInitUniformColumns(Layout);
|
ui_WidgetInitUniformColumns(Layout);
|
||||||
|
return Layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ui_column_size_rule
|
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_BeginRow(ui_interface* Interface, u32 ColumnsMax, ui_column_spec* ColumnRules)
|
||||||
{
|
{
|
||||||
ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false);
|
ui_widget* Layout = ui_PushLayout(Interface, MakeString("Row"), false);
|
||||||
ui_WidgetCreateColumns(Layout, ColumnsMax, Interface);
|
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
|
// 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 RowWidth = Rect2Width(Layout->Bounds);
|
||||||
r32 RemainingSpace = RowWidth;
|
r32 RemainingSpace = RowWidth;
|
||||||
u32 FillColumnsCount = 0;
|
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);
|
Column->XMax = Column->XMin + Max(0, ColumnWidth);
|
||||||
ColumnStartX = Column->XMax;
|
ColumnStartX = Column->XMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ui_EndRow(ui_interface* Interface)
|
ui_EndRow(ui_interface* Interface)
|
||||||
{
|
{
|
||||||
ui_PopLayout(Interface);
|
ui_PopLayout(Interface);
|
||||||
//ui_widget* Layout = Interface->ActiveLayout;
|
|
||||||
//Layout->DrawHorizontal = false;
|
|
||||||
//Layout->RowYAt -= (Layout->RowHeight + Layout->Margin.y);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static rect2
|
static rect2
|
||||||
|
@ -771,10 +857,12 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds)
|
||||||
Widget->Bounds = Bounds;
|
Widget->Bounds = Bounds;
|
||||||
SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget);
|
SLLPushOrInit(Interface->ActiveLayout->ChildrenRoot, Interface->ActiveLayout->ChildrenHead, Widget);
|
||||||
Interface->ActiveLayout->ChildCount += 1;
|
Interface->ActiveLayout->ChildCount += 1;
|
||||||
|
ui_CommitBounds(Widget->Parent, Widget->Bounds);
|
||||||
|
|
||||||
if (ui_WidgetIsFlagSet(*Widget, UIWidgetFlag_Clickable))
|
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))
|
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;
|
Interface->HotWidget = Widget->Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState) &&
|
if (MouseButtonHeldDown(Interface->Mouse.LeftButtonState) &&
|
||||||
PointIsInRect(Widget->Bounds, Interface->Mouse.DownPos))
|
PointIsInRect(Widget->Bounds, Interface->Mouse.DownPos))
|
||||||
{
|
{
|
||||||
|
@ -802,8 +889,6 @@ ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget, rect2 Bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(Widget->Parent != 0);
|
Assert(Widget->Parent != 0);
|
||||||
ui_CommitBounds(Widget->Parent, Widget->Bounds);
|
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,7 +896,7 @@ internal ui_eval_result
|
||||||
ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget)
|
ui_EvaluateWidget(ui_interface* Interface, ui_widget* Widget)
|
||||||
{
|
{
|
||||||
ui_widget* Layout = Interface->ActiveLayout;
|
ui_widget* Layout = Interface->ActiveLayout;
|
||||||
rect2 Bounds = ui_ReserveBounds(Layout, true);
|
rect2 Bounds = ui_ReserveBounds(Interface, Layout, true);
|
||||||
return ui_EvaluateWidget(Interface, Widget, Bounds);
|
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)
|
ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_result EvalResult, r32 Value, r32 MinValue, r32 MaxValue)
|
||||||
{
|
{
|
||||||
r32 NewValue = Value;
|
r32 NewValue = Value;
|
||||||
|
ui_widget_retained_state* State = ui_GetOrCreateRetainedState(Interface, Widget);
|
||||||
ui_widget_retained_state* State = ui_GetRetainedState(Interface, Widget->Id);
|
|
||||||
if (!State)
|
|
||||||
{
|
|
||||||
State = ui_CreateRetainedState(Interface, Widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EvalResult.Clicked)
|
if (EvalResult.Clicked)
|
||||||
{
|
{
|
||||||
|
@ -1038,7 +1118,7 @@ ui_EvaluateRangeSlider(ui_interface* Interface, ui_widget* Widget, ui_eval_resul
|
||||||
}
|
}
|
||||||
|
|
||||||
NewValue = Clamp(MinValue, NewValue, MaxValue);
|
NewValue = Clamp(MinValue, NewValue, MaxValue);
|
||||||
Widget->HorizontalFillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1);
|
Widget->FillPercent = RemapR32(NewValue, MinValue, MaxValue, 0, 1);
|
||||||
return NewValue;
|
return NewValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1083,21 +1163,86 @@ ui_Toggle(ui_interface* Interface, gs_string Text, bool Value)
|
||||||
ui_eval_result Eval = ui_EvaluateWidget(Interface, Widget);
|
ui_eval_result Eval = ui_EvaluateWidget(Interface, Widget);
|
||||||
|
|
||||||
bool Result = Eval.Clicked ? !Value : Value;
|
bool Result = Eval.Clicked ? !Value : Value;
|
||||||
Widget->HorizontalFillPercent = Result ? 1.0f : 0.0f;
|
Widget->FillPercent = Result ? 1.0f : 0.0f;
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void
|
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
|
internal void
|
||||||
ui_EndList(ui_interface* Interface)
|
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
|
// 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
|
internal r32
|
||||||
EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, v2 Min, v2 Max, r32 Current, mouse_state Mouse)
|
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;
|
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
|
#define INTERFACE_H
|
||||||
#endif // INTERFACE_H
|
#endif // INTERFACE_H
|
|
@ -927,6 +927,10 @@ Range2Union(range2 A, range2 B)
|
||||||
Result.Min.y = Max(A.Min.y, B.Min.y);
|
Result.Min.y = Max(A.Min.y, B.Min.y);
|
||||||
Result.Max.x = Min(A.Max.x, B.Max.x);
|
Result.Max.x = Min(A.Max.x, B.Max.x);
|
||||||
Result.Max.y = Min(A.Max.y, B.Max.y);
|
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;
|
return Result;
|
||||||
}
|
}
|
||||||
internal range3
|
internal range3
|
||||||
|
@ -949,6 +953,41 @@ Rect2GetRectLocalPoint(rect2 Rect, v2 Point)
|
||||||
return Result;
|
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
|
// Ray
|
||||||
|
|
Loading…
Reference in New Issue