diff --git a/native/cmd/lich-native/topbar.go b/native/cmd/lich-native/topbar.go index a228dd3a..b8792121 100644 --- a/native/cmd/lich-native/topbar.go +++ b/native/cmd/lich-native/topbar.go @@ -142,7 +142,7 @@ func (t *topbar) layout(gtx C, th *ui.Theme, f topbarFrame) topbarAction { right := t.rightSide(gtx, th, f, &act) left := t.leftSide(gtx, th, f, &act) f.brandWidth = max(f.brandWidth-left, gtx.Dp(brandHeight)) - start := max(f.stripX, g+left+f.brandWidth+gtx.Dp(barGap)) + start := stripStart(f.stripX, g+left+f.brandWidth+gtx.Dp(barGap), gtx.Dp(tabRadius)) t.shift, f.stripX = start-f.stripX, start t.place(gtx, image.Pt(g+left, 0), func(gtx C) D { return t.brandButton(gtx, th, f) }) stripW := gtx.Constraints.Max.X - right - g - gtx.Dp(barGap) - f.stripX @@ -153,6 +153,16 @@ func (t *topbar) layout(gtx C, th *ui.Theme, f topbarFrame) topbarAction { return act } +// stripStart is where the tab strip starts: at the island's edge, or, when +// the window's own buttons and the brand reach past it, a fillet radius after +// them, the room the active first tab's left fillet draws in. +func stripStart(islandEdge, brandEnd, radius int) int { + if brandEnd <= islandEdge { + return islandEdge + } + return brandEnd + radius +} + // place lays w out at p. func (t *topbar) place(gtx C, p image.Point, w layout.Widget) { defer op.Offset(p).Push(gtx.Ops).Pop() diff --git a/native/cmd/lich-native/topbar_tabs.go b/native/cmd/lich-native/topbar_tabs.go index 23a774a7..4ed5311f 100644 --- a/native/cmd/lich-native/topbar_tabs.go +++ b/native/cmd/lich-native/topbar_tabs.go @@ -111,7 +111,13 @@ func (t *topbar) strip(gtx C, th *ui.Theme, f topbarFrame, act *topbarAction) D ids[i] = tab.ID } size := gtx.Constraints.Max - clipped := clip.Rect{Max: size}.Push(gtx.Ops) + // A strip pushed past the island's edge reaches left over the room + // stripStart left, where the active first tab's left fillet draws. + var filletRoom int + if t.shift > 0 { + filletRoom = gtx.Dp(tabRadius) + } + clipped := clip.Rect{Min: image.Pt(-filletRoom, 0), Max: size}.Push(gtx.Ops) tabs := t.list.Layout(gtx, 1, func(gtx C, _ int) D { return layout.Flex{Alignment: layout.Middle}.Layout(gtx, layout.Rigid(func(gtx C) D { diff --git a/native/cmd/lich-native/topbar_test.go b/native/cmd/lich-native/topbar_test.go index 46a7afad..a6abfc0d 100644 --- a/native/cmd/lich-native/topbar_test.go +++ b/native/cmd/lich-native/topbar_test.go @@ -96,3 +96,16 @@ func TestSettingsButtonOpensOnGlobalAfterAProjectScope(t *testing.T) { t.Errorf("the settings button opened on scope %q (open %v), want Global", u.settings.scope, u.settings.open) } } + +// Past the window's own buttons, the strip leaves the active first tab's +// left fillet a radius of room after the brand, where it would otherwise be +// cut off at the strip's edge. +func TestStripStartLeavesTheFilletRoom(t *testing.T) { + const island, radius = 44, 8 + if got := stripStart(island, 40, radius); got != island { + t.Errorf("brand short of the island: start %d, want the island's edge %d", got, island) + } + if got := stripStart(island, 120, radius); got != 120+radius { + t.Errorf("brand past the island: start %d, want %d", got, 120+radius) + } +}