From 87020cd48bff0f99ecd2dfe0a14cfa2d73eaa8e2 Mon Sep 17 00:00:00 2001 From: Vmarcelo49 Date: Mon, 29 Dec 2025 15:16:14 -0300 Subject: [PATCH 1/2] removed DrawFilledRect instance and replaced with FillRect added inLayoutCallback inside Context to avoid nested widgets --- context.go | 4 ++++ draw.go | 13 ++++++++++++- widget.go | 4 +++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index f1e7451..010098b 100644 --- a/context.go +++ b/context.go @@ -54,6 +54,10 @@ type Context struct { screenWidth int screenHeight int + // inLayoutCallback tracks if we're inside a widget's layout callback. + // This is used to prevent creating nested widgets unintentionally. + inLayoutCallback bool + err error } diff --git a/draw.go b/draw.go index 3c0383f..d8803b7 100644 --- a/draw.go +++ b/draw.go @@ -106,7 +106,7 @@ func (c *Context) draw(screen *ebiten.Image) { for cmd := range c.commands() { switch cmd.typ { case commandRect: - vector.DrawFilledRect( + vector.FillRect( target, float32(cmd.rect.rect.Min.X*scale), float32(cmd.rect.rect.Min.Y*scale), @@ -205,6 +205,17 @@ func (c *Context) drawIcon(icon icon, rect image.Rectangle, color color.Color) { // DrawOnlyWidget adds a widget that only draws the given function without user interaction. func (c *Context) DrawOnlyWidget(f func(screen *ebiten.Image)) { _ = c.wrapEventHandlerAndError(func() (EventHandler, error) { + // If we're inside a layout callback (e.g., GridCell), just add the draw command + // without creating a nested widget + if c.inLayoutCallback { + c.setClip(c.clipRect()) + defer c.setClip(unclippedRect) + cmd := c.appendCommand(commandDraw) + cmd.draw.f = f + return nil, nil + } + + // Otherwise, create a widget normally _, _ = c.widget(widgetID{}, 0, nil, nil, func(bounds image.Rectangle) { c.setClip(c.clipRect()) defer c.setClip(unclippedRect) diff --git a/widget.go b/widget.go index e0adaa6..0e7d4ca 100644 --- a/widget.go +++ b/widget.go @@ -139,7 +139,9 @@ func (c *Context) widget(id widgetID, opt option, layout func(bounds image.Recta err = err2 } }() + c.inLayoutCallback = true layout(bounds) + c.inLayoutCallback = false } wasFocused := c.handleInputForWidget(id, bounds, opt) @@ -148,7 +150,7 @@ func (c *Context) widget(id widgetID, opt option, layout func(bounds image.Recta e = handleInput(bounds, wasFocused) } // Handling input is still needed even if the widget is out of bounds, especially for Header. - if !c.currentContainer().layout.BodyBounds.Overlaps(bounds) { + if !c.clipRect().Overlaps(bounds) { return e, nil } From c51eb48d5b5c572a2932a48c0c1e44f9af165092 Mon Sep 17 00:00:00 2001 From: vmarcelo Date: Mon, 29 Dec 2025 15:33:29 -0300 Subject: [PATCH 2/2] clarify comments --- context.go | 3 +-- draw.go | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/context.go b/context.go index 010098b..5ab513d 100644 --- a/context.go +++ b/context.go @@ -54,8 +54,7 @@ type Context struct { screenWidth int screenHeight int - // inLayoutCallback tracks if we're inside a widget's layout callback. - // This is used to prevent creating nested widgets unintentionally. + // inLayoutCallback is true during a widget layout callback to block nested widgets. inLayoutCallback bool err error diff --git a/draw.go b/draw.go index d8803b7..51865f8 100644 --- a/draw.go +++ b/draw.go @@ -205,8 +205,7 @@ func (c *Context) drawIcon(icon icon, rect image.Rectangle, color color.Color) { // DrawOnlyWidget adds a widget that only draws the given function without user interaction. func (c *Context) DrawOnlyWidget(f func(screen *ebiten.Image)) { _ = c.wrapEventHandlerAndError(func() (EventHandler, error) { - // If we're inside a layout callback (e.g., GridCell), just add the draw command - // without creating a nested widget + // If we're inside a layout callback like GridCell we just draw instead of putting it in a nested widget if c.inLayoutCallback { c.setClip(c.clipRect()) defer c.setClip(unclippedRect) @@ -215,7 +214,6 @@ func (c *Context) DrawOnlyWidget(f func(screen *ebiten.Image)) { return nil, nil } - // Otherwise, create a widget normally _, _ = c.widget(widgetID{}, 0, nil, nil, func(bounds image.Rectangle) { c.setClip(c.clipRect()) defer c.setClip(unclippedRect)