From 7383f73a5b1589d3257b44407e46adfe987e2530 Mon Sep 17 00:00:00 2001 From: Physcik Date: Mon, 2 Feb 2026 02:00:29 +0500 Subject: Span system rework pt 1 --- engine/UI/Button.go | 3 ++ engine/UI/FlexElement.go | 70 ++++++++++++++++++++++++++++++++++++++++++++ engine/UI/GridColumn.go | 26 +++++++++++++++++ engine/UI/GridRow.go | 75 ++++++++++++++++++++++++++++++++++++++++++++---- engine/UI/Label.go | 3 ++ engine/UI/Menu.go | 54 +++++++++------------------------- engine/UI/Style.go | 9 ++++++ engine/main.go | 15 ++++++---- 8 files changed, 204 insertions(+), 51 deletions(-) create mode 100644 engine/UI/FlexElement.go create mode 100644 engine/UI/GridColumn.go diff --git a/engine/UI/Button.go b/engine/UI/Button.go index 8d336a9..a8b9168 100644 --- a/engine/UI/Button.go +++ b/engine/UI/Button.go @@ -22,6 +22,9 @@ type Button struct { func (base *Button) Init(parent *Menu) { base.DisplayElement.Init(parent) + if base.WidthWeight == 0 { + base.WidthWeight = 1 + } switch base.EventType { case OnClick: diff --git a/engine/UI/FlexElement.go b/engine/UI/FlexElement.go new file mode 100644 index 0000000..233b89f --- /dev/null +++ b/engine/UI/FlexElement.go @@ -0,0 +1,70 @@ +package ui + +import rl "github.com/gen2brain/raylib-go/raylib" + +// A dynamically shrinking element that contains other elements +type flexElement interface { + GetElements() []UIElement + GetSpacing() float32 + RecalculateCache(*rl.Rectangle) +} + +// Calculates the element weight to pixel ratio +func getWeightToPixelsRatio(base flexElement, totalSpace float32) float32 { + var elements = base.GetElements() + var totalWeights float32 = 0 + for _, v := range elements { + totalWeights += v.GetOccupationWeight() + } + var spacingPx = totalSpace * base.GetSpacing() + var totalSpacing = float32(len(elements) - 1) * spacingPx + if totalSpace < 0 { + totalSpace = 0 + } + return (totalSpace - totalSpacing) / totalWeights +} + + +type layoutCache struct { + // The screen resolution the cache was calculated for + ScreenResolution rl.Vector2 + // The resolution the cache was calculated for + SpanResolution rl.Vector2 + // Horizontal offset in pixels + OffsetX float32 + // Vertical offset in pixels + OffsetY float32 + // The X size of a row + Width float32 + // The Y size of a row + Height float32 + // The horizontal start and end of each row. + // Index of an array is representive with row index + RowLocations []rl.Vector2 +} + +func (base layoutCache) IsValid() bool { + return base.ScreenResolution.X == float32(rl.GetScreenWidth()) && + base.ScreenResolution.Y == float32(rl.GetScreenHeight()) +} + +func (base *layoutCache) CalculateOffsets(X float32, Y float32, paddingX float32, paddingY float32) { + base.OffsetX = (X * paddingX) + base.OffsetY = (Y * paddingY) + base.Width = X - base.OffsetX * 2 + base.Height = Y - base.OffsetY * 2 +} + +func (base *layoutCache) CalculateRowsLocations (rows []UIElement, WeightToPixels float32, spacing float32, baseOffset float32) { + base.RowLocations = make([]rl.Vector2, len(rows)) + var ptr float32 = baseOffset + for i, v := range rows { + // The spacing should be accounted for in the WeightToPixels param + var elemSpace = (WeightToPixels * v.GetOccupationWeight()) + base.RowLocations[i] = rl.Vector2 { + X: ptr, + Y: elemSpace, + } + ptr += elemSpace + spacing + } +} diff --git a/engine/UI/GridColumn.go b/engine/UI/GridColumn.go new file mode 100644 index 0000000..02d441f --- /dev/null +++ b/engine/UI/GridColumn.go @@ -0,0 +1,26 @@ +package ui + +import rl "github.com/gen2brain/raylib-go/raylib" + +type GridColumn struct { + Weight float32 + Spacing float32 + Elements []UIElement + + cache layoutCache +} + +func (base *GridColumn) Init(*Menu) { +} + +func (base *GridColumn) Destroy() { +} + +// Gets the scale width of the element. Works similar to CSS's 'flex-grow' +func (base *GridColumn) GetOccupationWeight() float32 { + return base.Weight +} + +// Draw the element with the given size +func (base *GridColumn) Draw(*rl.Rectangle) { +} diff --git a/engine/UI/GridRow.go b/engine/UI/GridRow.go index bb9ffe3..4e222a7 100644 --- a/engine/UI/GridRow.go +++ b/engine/UI/GridRow.go @@ -1,25 +1,90 @@ package ui -import rl "github.com/gen2brain/raylib-go/raylib" +import ( + "image/color" + + rl "github.com/gen2brain/raylib-go/raylib" +) + +var defaultGridPadding float32 = 0 +var defaultGridRoundness float32 = 0 + +var defaultGridStyle = &Style { + BacgroundColor: &color.RGBA{0, 0, 0, 0}, + FontColor: &rl.DarkGray, + Padding: &defaultGridPadding, + Roundness: &defaultGridRoundness, +} type GridRow struct { // A portion of the screen the row will occupy. Works similar to CSS's 'flex-grow' HeightWeight float32 // The objects that lay in this row Objects []UIElement + // Spaces between the columns + Spacing float32 + // Styling preferences + Style *Style location rl.Rectangle + cache layoutCache +} + +func (base *GridRow) GetElements() []UIElement { + return base.Objects +} + +func (base *GridRow) GetSpacing() float32 { + return base.Spacing } func (base *GridRow) Init(parent *Menu) { + base.Style = InitStyle(base.Style, defaultGridStyle) for _, v := range base.Objects { v.Init(parent) } + base.cache = layoutCache { + ScreenResolution: rl.Vector2{ X:0, Y:0 }, + } } -func (base *GridRow) Draw(span rl.Rectangle) { - // TODO: Add horizontal spacing - for _, v := range base.Objects { - v.Draw(&span) +func (base *GridRow) Destroy() { +} + +// Gets the scale width of the element. Works similar to CSS's 'flex-grow' +func (base *GridRow) GetOccupationWeight() float32 { + return base.HeightWeight +} + +// Draw the element with the given size +func (base *GridRow) Draw(span *rl.Rectangle) { + if !base.cache.IsValid() { + base.RecalculateCache(span) + } + for i, v := range base.Objects { + var offset = base.cache.RowLocations[i] + var elemSpan = rl.Rectangle { + X: offset.X, + Y: span.Y + *base.Style.Padding, + Width: offset.Y, + Height: span.Height - *base.Style.Padding * 2, + } + v.Draw(&elemSpan) + } +} + +func (base *GridRow) RecalculateCache(span *rl.Rectangle) { + base.cache.SpanResolution = rl.Vector2{ + X: span.Width, + Y: span.Height, + } + base.cache.ScreenResolution = rl.Vector2 { + X: float32(rl.GetScreenWidth()), + Y: float32(rl.GetScreenHeight()), } + base.cache.CalculateOffsets(span.Width, span.Height, *base.Style.Padding, *base.Style.Padding) + var weightToScale = getWeightToPixelsRatio(base, base.cache.Width) + var spacingPx = base.Spacing * span.Width + rl.TraceLog(rl.LogInfo, "Spacing: %v (%v px)", base.Spacing, spacingPx) + base.cache.CalculateRowsLocations(base.Objects, weightToScale, spacingPx, span.X) } diff --git a/engine/UI/Label.go b/engine/UI/Label.go index f412eff..e864c85 100644 --- a/engine/UI/Label.go +++ b/engine/UI/Label.go @@ -25,6 +25,9 @@ type Label struct { func (base *Label) Init(*Menu) { base.Style.FillMissing(defaultLabelStyle) + if base.WidthWeight == 0 { + base.WidthWeight = 1 + } } func (base *Label) Destroy() { diff --git a/engine/UI/Menu.go b/engine/UI/Menu.go index e046a0e..8f9328f 100644 --- a/engine/UI/Menu.go +++ b/engine/UI/Menu.go @@ -16,46 +16,11 @@ type Menu struct { // Spaces between the rows Spacing float32 // A horizontal line of elements - Rows []*GridRow + Rows []UIElement cache *layoutCache } -// The pixel scalin -type layoutCache struct { - // The resolution the cache was calculated for - ScreenResolution rl.Vector2 - // Horizontal offset in pixels - OffsetX float32 - // Vertical offset in pixels - OffsetY float32 - // The Y size of a row - Width float32 - // The horizontal start and end of each row. - // Index of an array is representive with row index - RowLocations []rl.Vector2 -} - -func (base *layoutCache) CalculateOffsets(paddingX float32, paddingY float32) { - base.OffsetX = (base.ScreenResolution.X * paddingX) - base.OffsetY = (base.ScreenResolution.Y * paddingY) - base.Width = base.ScreenResolution.X - base.OffsetX * 2 -} - -func (base *layoutCache) CalculateRowsLocations (rows []*GridRow, WeightToPixels float32, spacing float32) { - var spacingPixels = (base.ScreenResolution.Y * spacing) - base.RowLocations = make([]rl.Vector2, len(rows)) - var y float32 = base.OffsetY - for i, v := range rows { - var rowHeight = (WeightToPixels * v.HeightWeight) - base.RowLocations[i] = rl.Vector2 { - X: y, - Y: rowHeight, - } - y += rowHeight + spacingPixels - } -} - func (base *Menu) Create(manager *coreobjects.SceneManager) { base.manager = manager base.cache = &layoutCache{} @@ -81,7 +46,7 @@ func (base *Menu) Draw() { for i, v := range base.Rows { var verticalSpacing = base.cache.RowLocations[i] - v.Draw(rl.Rectangle{ + v.Draw(&rl.Rectangle{ X: base.cache.OffsetX, Y: verticalSpacing.X, Width: base.cache.Width, @@ -126,9 +91,18 @@ func (base *Menu) generateLayout() { X: float32(rl.GetScreenWidth()), Y: float32(rl.GetScreenHeight()), } - base.cache.CalculateOffsets(base.PaddingX, base.PaddingY) + base.cache.SpanResolution = rl.Vector2{ + X: float32(rl.GetScreenWidth()), + Y: float32(rl.GetScreenHeight()), + } + base.cache.CalculateOffsets( + float32(rl.GetScreenWidth()), + float32(rl.GetScreenHeight()), + base.PaddingX, + base.PaddingY) var weightToScale = base.getWeightToPixelRatio() - base.cache.CalculateRowsLocations(base.Rows, weightToScale, base.Spacing) + var spacingPx = base.cache.Width * base.Spacing + base.cache.CalculateRowsLocations(base.Rows, weightToScale, spacingPx, base.cache.OffsetY) } // Sums up all the weights @@ -136,7 +110,7 @@ func (base *Menu) getWeightToPixelRatio() float32 { var rowsAmount = len(base.Rows) var sum float32 = 0 for _, v := range base.Rows { - sum += v.HeightWeight + sum += v.GetOccupationWeight() } var spacingPixels = base.cache.ScreenResolution.Y * base.Spacing var spacing = float32(rowsAmount - 1) * spacingPixels diff --git a/engine/UI/Style.go b/engine/UI/Style.go index 091a6a3..1e05bcf 100644 --- a/engine/UI/Style.go +++ b/engine/UI/Style.go @@ -29,3 +29,12 @@ func (base *Style) FillMissing(defaultStyle *Style) { base.Roundness = defaultLabelStyle.Roundness } } + +// Ensures that the provided style is not nil and fills in gaps with default style +func InitStyle(provided *Style, defaultStyle *Style) *Style { + if provided == nil { + return defaultStyle + } + provided.FillMissing(defaultStyle) + return provided +} diff --git a/engine/main.go b/engine/main.go index 0d2e657..ea29794 100644 --- a/engine/main.go +++ b/engine/main.go @@ -42,14 +42,17 @@ func menu_test() *ui.Menu { PaddingX: 0.05, PaddingY: 0.1, Spacing: 0.025, - Rows: []*ui.GridRow { - { + Rows: []ui.UIElement { + &ui.GridRow { HeightWeight: 1, + Spacing: 0.01, Objects: []ui.UIElement { - &ui.Label{ Text: "Ruines of Rafdolon" }, + &ui.Label{ Text: "First piece" }, + &ui.Label{ Text: "Wide piece", WidthWeight: 2 }, + &ui.Label{ Text: "Another piece" }, }, }, - { + &ui.GridRow { HeightWeight: 2, Objects: []ui.UIElement { &ui.Button { @@ -63,10 +66,10 @@ func menu_test() *ui.Menu { }, }, }, - { + &ui.GridRow { HeightWeight: 1, Objects: []ui.UIElement { - &ui.Label{ Text: "Test text" }, + &ui.Label{ Text: "A very very long text that is bigger than a window" }, }, }, }, -- cgit v1.3