fix(core): center layers between opposing anchors
- commit
- aba8c9ff1c4ebebc1a73758e903225813f57ea5e
- author
- brice · · 2026-09-23 16:17 UTC
- parent
- d8ac0f6
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +27 -8
M internal/core/layers.go +23 -8
| @@ -20,18 +20,33 @@ func arrangeLayers(outW, outH int, layers []ports.LayerSurface) (placed []ports. | |||
| 20 | 20 | bounds = full | |
| 21 | 21 | } | |
| 22 | 22 | top, right, bottom, left := int(s.Margin[0]), int(s.Margin[1]), int(s.Margin[2]), int(s.Margin[3]) | |
| 23 | - | x, y := bounds.X+(bounds.W-s.Width)/2, bounds.Y+(bounds.H-s.Height)/2 | |
| 24 | - | if s.Anchor&ports.AnchorLeft != 0 { | |
| 23 | + | w, h := s.Width, s.Height | |
| 24 | + | x, y := bounds.X+(bounds.W-w)/2, bounds.Y+(bounds.H-h)/2 | |
| 25 | + | switch s.Anchor & (ports.AnchorLeft | ports.AnchorRight) { | |
| 26 | + | case ports.AnchorLeft | ports.AnchorRight: | |
| 27 | + | span := bounds.W - left - right | |
| 28 | + | if w == 0 { | |
| 29 | + | w = span | |
| 30 | + | } | |
| 31 | + | x = bounds.X + left + (span-w)/2 | |
| 32 | + | case ports.AnchorLeft: | |
| 25 | 33 | x = bounds.X + left | |
| 26 | - | } else if s.Anchor&ports.AnchorRight != 0 { | |
| 27 | - | x = bounds.X + bounds.W - s.Width - right | |
| 34 | + | case ports.AnchorRight: | |
| 35 | + | x = bounds.X + bounds.W - w - right | |
| 28 | 36 | } | |
| 29 | - | if s.Anchor&ports.AnchorTop != 0 { | |
| 37 | + | switch s.Anchor & (ports.AnchorTop | ports.AnchorBottom) { | |
| 38 | + | case ports.AnchorTop | ports.AnchorBottom: | |
| 39 | + | span := bounds.H - top - bottom | |
| 40 | + | if h == 0 { | |
| 41 | + | h = span | |
| 42 | + | } | |
| 43 | + | y = bounds.Y + top + (span-h)/2 | |
| 44 | + | case ports.AnchorTop: | |
| 30 | 45 | y = bounds.Y + top | |
| 31 | - | } else if s.Anchor&ports.AnchorBottom != 0 { | |
| 32 | - | y = bounds.Y + bounds.H - s.Height - bottom | |
| 46 | + | case ports.AnchorBottom: | |
| 47 | + | y = bounds.Y + bounds.H - h - bottom | |
| 33 | 48 | } | |
| 34 | - | placed = append(placed, ports.SceneLayer{ID: s.ID, Layer: s.Layer, Rect: ports.Rect{X: x, Y: y, W: s.Width, H: s.Height}}) | |
| 49 | + | placed = append(placed, ports.SceneLayer{ID: s.ID, Layer: s.Layer, Rect: ports.Rect{X: x, Y: y, W: w, H: h}}) | |
| 35 | 50 | if s.ExclusiveZone <= 0 { | |
| 36 | 51 | continue | |
| 37 | 52 | } | |
| @@ -20,18 +20,33 @@ func arrangeLayers(outW, outH int, layers []ports.LayerSurface) (placed []ports. | |||||
| 20 | bounds = full | 20 | bounds = full | ||
| 21 | } | 21 | } | ||
| 22 | top, right, bottom, left := int(s.Margin[0]), int(s.Margin[1]), int(s.Margin[2]), int(s.Margin[3]) | 22 | top, right, bottom, left := int(s.Margin[0]), int(s.Margin[1]), int(s.Margin[2]), int(s.Margin[3]) | ||
| 23 | - | x, y := bounds.X+(bounds.W-s.Width)/2, bounds.Y+(bounds.H-s.Height)/2 | 23 | + | w, h := s.Width, s.Height |
| 24 | - | if s.Anchor&ports.AnchorLeft != 0 { | 24 | + | x, y := bounds.X+(bounds.W-w)/2, bounds.Y+(bounds.H-h)/2 |
| 25 | + | switch s.Anchor & (ports.AnchorLeft | ports.AnchorRight) { | |||
| 26 | + | case ports.AnchorLeft | ports.AnchorRight: | |||
| 27 | + | span := bounds.W - left - right | |||
| 28 | + | if w == 0 { | |||
| 29 | + | w = span | |||
| 30 | + | } | |||
| 31 | + | x = bounds.X + left + (span-w)/2 | |||
| 32 | + | case ports.AnchorLeft: | |||
| 25 | x = bounds.X + left | 33 | x = bounds.X + left | ||
| 26 | - | } else if s.Anchor&ports.AnchorRight != 0 { | 34 | + | case ports.AnchorRight: |
| 27 | - | x = bounds.X + bounds.W - s.Width - right | 35 | + | x = bounds.X + bounds.W - w - right |
| 28 | } | 36 | } | ||
| 29 | - | if s.Anchor&ports.AnchorTop != 0 { | 37 | + | switch s.Anchor & (ports.AnchorTop | ports.AnchorBottom) { |
| 38 | + | case ports.AnchorTop | ports.AnchorBottom: | |||
| 39 | + | span := bounds.H - top - bottom | |||
| 40 | + | if h == 0 { | |||
| 41 | + | h = span | |||
| 42 | + | } | |||
| 43 | + | y = bounds.Y + top + (span-h)/2 | |||
| 44 | + | case ports.AnchorTop: | |||
| 30 | y = bounds.Y + top | 45 | y = bounds.Y + top | ||
| 31 | - | } else if s.Anchor&ports.AnchorBottom != 0 { | 46 | + | case ports.AnchorBottom: |
| 32 | - | y = bounds.Y + bounds.H - s.Height - bottom | 47 | + | y = bounds.Y + bounds.H - h - bottom |
| 33 | } | 48 | } | ||
| 34 | - | placed = append(placed, ports.SceneLayer{ID: s.ID, Layer: s.Layer, Rect: ports.Rect{X: x, Y: y, W: s.Width, H: s.Height}}) | 49 | + | placed = append(placed, ports.SceneLayer{ID: s.ID, Layer: s.Layer, Rect: ports.Rect{X: x, Y: y, W: w, H: h}}) |
| 35 | if s.ExclusiveZone <= 0 { | 50 | if s.ExclusiveZone <= 0 { | ||
| 36 | continue | 51 | continue | ||
| 37 | } | 52 | } | ||
M internal/core/layers_test.go +4 -0
| @@ -20,6 +20,10 @@ func TestArrangeLayers(t *testing.T) { | |||
| 20 | 20 | {"bottom margin", []ports.LayerSurface{{Anchor: ports.AnchorBottom, Width: 100, Height: 20, ExclusiveZone: 20, Margin: [4]int32{0, 0, 5, 0}}}, []ports.Rect{{X: 910, Y: 1055, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1055}}, | |
| 21 | 21 | {"left dock", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorTop | ports.AnchorBottom, Width: 40, Height: 1080, ExclusiveZone: 40}}, []ports.Rect{{W: 40, H: 1080}}, ports.Rect{X: 40, W: 1880, H: 1080}}, | |
| 22 | 22 | {"center", []ports.LayerSurface{{Width: 100, Height: 40, Layer: ports.LayerOverlay}}, []ports.Rect{{X: 910, Y: 520, W: 100, H: 40}}, ports.Rect{W: 1920, H: 1080}}, | |
| 23 | + | {"opposing horizontal anchors with margins", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorRight, Width: 100, Height: 20, Margin: [4]int32{0, 30, 0, 10}}}, []ports.Rect{{X: 900, Y: 530, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |
| 24 | + | {"top only", []ports.LayerSurface{{Anchor: ports.AnchorTop, Width: 100, Height: 20, Margin: [4]int32{7, 0, 0, 0}}}, []ports.Rect{{X: 910, Y: 7, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |
| 25 | + | {"full span between margins", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorRight | ports.AnchorTop, Height: 20, Margin: [4]int32{7, 30, 0, 10}}}, []ports.Rect{{X: 10, Y: 7, W: 1880, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |
| 26 | + | {"opposing vertical anchors with margins", []ports.LayerSurface{{Anchor: ports.AnchorTop | ports.AnchorBottom, Width: 100, Height: 20, Margin: [4]int32{10, 0, 30, 0}}}, []ports.Rect{{X: 910, Y: 520, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |
| 23 | 27 | {"minus one", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: ports.AnchorTop, Width: 100, Height: 20, ExclusiveZone: -1}}, []ports.Rect{{W: 1920, H: 30}, {X: 910, W: 100, H: 20}}, ports.Rect{Y: 30, W: 1920, H: 1050}}, | |
| 24 | 28 | {"stack", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: bar.Anchor, Width: 1920, Height: 20, ExclusiveZone: 20}}, []ports.Rect{{W: 1920, H: 30}, {Y: 30, W: 1920, H: 20}}, ports.Rect{Y: 50, W: 1920, H: 1030}}, | |
| 25 | 29 | } | |
| @@ -20,6 +20,10 @@ func TestArrangeLayers(t *testing.T) { | |||||
| 20 | {"bottom margin", []ports.LayerSurface{{Anchor: ports.AnchorBottom, Width: 100, Height: 20, ExclusiveZone: 20, Margin: [4]int32{0, 0, 5, 0}}}, []ports.Rect{{X: 910, Y: 1055, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1055}}, | 20 | {"bottom margin", []ports.LayerSurface{{Anchor: ports.AnchorBottom, Width: 100, Height: 20, ExclusiveZone: 20, Margin: [4]int32{0, 0, 5, 0}}}, []ports.Rect{{X: 910, Y: 1055, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1055}}, | ||
| 21 | {"left dock", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorTop | ports.AnchorBottom, Width: 40, Height: 1080, ExclusiveZone: 40}}, []ports.Rect{{W: 40, H: 1080}}, ports.Rect{X: 40, W: 1880, H: 1080}}, | 21 | {"left dock", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorTop | ports.AnchorBottom, Width: 40, Height: 1080, ExclusiveZone: 40}}, []ports.Rect{{W: 40, H: 1080}}, ports.Rect{X: 40, W: 1880, H: 1080}}, | ||
| 22 | {"center", []ports.LayerSurface{{Width: 100, Height: 40, Layer: ports.LayerOverlay}}, []ports.Rect{{X: 910, Y: 520, W: 100, H: 40}}, ports.Rect{W: 1920, H: 1080}}, | 22 | {"center", []ports.LayerSurface{{Width: 100, Height: 40, Layer: ports.LayerOverlay}}, []ports.Rect{{X: 910, Y: 520, W: 100, H: 40}}, ports.Rect{W: 1920, H: 1080}}, | ||
| 23 | + | {"opposing horizontal anchors with margins", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorRight, Width: 100, Height: 20, Margin: [4]int32{0, 30, 0, 10}}}, []ports.Rect{{X: 900, Y: 530, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |||
| 24 | + | {"top only", []ports.LayerSurface{{Anchor: ports.AnchorTop, Width: 100, Height: 20, Margin: [4]int32{7, 0, 0, 0}}}, []ports.Rect{{X: 910, Y: 7, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |||
| 25 | + | {"full span between margins", []ports.LayerSurface{{Anchor: ports.AnchorLeft | ports.AnchorRight | ports.AnchorTop, Height: 20, Margin: [4]int32{7, 30, 0, 10}}}, []ports.Rect{{X: 10, Y: 7, W: 1880, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |||
| 26 | + | {"opposing vertical anchors with margins", []ports.LayerSurface{{Anchor: ports.AnchorTop | ports.AnchorBottom, Width: 100, Height: 20, Margin: [4]int32{10, 0, 30, 0}}}, []ports.Rect{{X: 910, Y: 520, W: 100, H: 20}}, ports.Rect{W: 1920, H: 1080}}, | |||
| 23 | {"minus one", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: ports.AnchorTop, Width: 100, Height: 20, ExclusiveZone: -1}}, []ports.Rect{{W: 1920, H: 30}, {X: 910, W: 100, H: 20}}, ports.Rect{Y: 30, W: 1920, H: 1050}}, | 27 | {"minus one", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: ports.AnchorTop, Width: 100, Height: 20, ExclusiveZone: -1}}, []ports.Rect{{W: 1920, H: 30}, {X: 910, W: 100, H: 20}}, ports.Rect{Y: 30, W: 1920, H: 1050}}, | ||
| 24 | {"stack", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: bar.Anchor, Width: 1920, Height: 20, ExclusiveZone: 20}}, []ports.Rect{{W: 1920, H: 30}, {Y: 30, W: 1920, H: 20}}, ports.Rect{Y: 50, W: 1920, H: 1030}}, | 28 | {"stack", []ports.LayerSurface{bar, {Layer: ports.LayerTop, Anchor: bar.Anchor, Width: 1920, Height: 20, ExclusiveZone: 20}}, []ports.Rect{{W: 1920, H: 30}, {Y: 30, W: 1920, H: 20}}, ports.Rect{Y: 50, W: 1920, H: 1030}}, | ||
| 25 | } | 29 | } | ||