From 3fc28fd54b08b14c3082ebe7a15665efe809b803 Mon Sep 17 00:00:00 2001 From: Greg Pomerantz Date: Sat, 9 May 2026 19:17:56 -0400 Subject: [PATCH] =?UTF-8?q?Document=20background=20drawing=20with=20clips?= =?UTF-8?q?=20=E2=80=94=20use=20push/pop,=20not=20op.Record=20macro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/layout_rendering.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc/layout_rendering.md b/doc/layout_rendering.md index bfcba9f..02008de 100644 --- a/doc/layout_rendering.md +++ b/doc/layout_rendering.md @@ -627,6 +627,33 @@ func (r *Renderer) drawBottomBar(gtx layout.Context, bb BottomBar, constraints W - **Don't mix Dp and Px**: The compiler will catch it. Use explicit conversions. - **Don't pass pixels as Dp to EditorLayout**: `main.go` must convert `app.ConfigEvent` pixels to Dp before passing to the logic layer. +## 9.6 Background Drawing with Clips + +When drawing backgrounds (rectangles with solid colors), use `clip.Rect{...}.Push(gtx.Ops)` followed immediately by `clip.Pop()`. **Never use `op.Record`/`m.Stop()` macros for simple background clips** — the macro leaves the clip on the stack, preventing subsequent elements from drawing. + +**Correct pattern**: +```go +bgClip := clip.Rect{ + Min: image.Point{X: pxMinX, Y: pxMinY}, + Max: image.Point{X: pxMaxX, Y: pxMaxY}, +}.Push(gtx.Ops) +paint.ColorOp{Color: bgColor}.Add(gtx.Ops) +paint.PaintOp{}.Add(gtx.Ops) +bgClip.Pop() // Immediately pop — clip stack must be clean +``` + +**Wrong pattern** (leaves clip on stack): +```go +m := op.Record(gtx.Ops) +clip.Rect{...}.Op().Push(gtx.Ops) // Push inside macro +paint.ColorOp{...}.Add(gtx.Ops) +paint.PaintOp{}.Add(gtx.Ops) +call := m.Stop() +call.Add(gtx.Ops) // When replayed, clip is pushed but never popped! +``` + +**Why this matters**: When the StatusBar draws its background with a macro, the clip inside is pushed during macro replay but never popped. The BottomBar then draws while that stale clip is still active, causing it to be clipped out of visibility. + ## 10. Summary - **Always** use `fixed.I(gtx.Sp(size))` for `PxPerEm`