fix(overview): derive boundary dividers from rendered envelopes
- commit
- da243964d5cb85d3265b24b87b6190427e6fd1d0
- author
- brice · · 2026-10-06 14:34 UTC
- parent
- 6ee8ac0
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +41 -1
M internal/core/core.go +1 -1
| @@ -627,7 +627,7 @@ func (c *Core) publishFrame(ctx context.Context, only *screen) error { | |||
| 627 | 627 | } | |
| 628 | 628 | if sc.mon.ov.open { | |
| 629 | 629 | // Frame the selection and separate numbered and named row groups. | |
| 630 | - | _, scene.Separators = sc.mon.overviewRows() | |
| 630 | + | scene.Separators = sc.mon.overviewDividers(layout) | |
| 631 | 631 | scene.Separators = append(scene.Separators, overviewOutline(layout, max(c.cfg.Border.Width, 2))...) | |
| 632 | 632 | } else { | |
| 633 | 633 | // Only the focused output lights the focused window's lines. | |
| @@ -627,7 +627,7 @@ func (c *Core) publishFrame(ctx context.Context, only *screen) error { | |||||
| 627 | } | 627 | } | ||
| 628 | if sc.mon.ov.open { | 628 | if sc.mon.ov.open { | ||
| 629 | // Frame the selection and separate numbered and named row groups. | 629 | // Frame the selection and separate numbered and named row groups. | ||
| 630 | - | _, scene.Separators = sc.mon.overviewRows() | 630 | + | scene.Separators = sc.mon.overviewDividers(layout) |
| 631 | scene.Separators = append(scene.Separators, overviewOutline(layout, max(c.cfg.Border.Width, 2))...) | 631 | scene.Separators = append(scene.Separators, overviewOutline(layout, max(c.cfg.Border.Width, 2))...) | ||
| 632 | } else { | 632 | } else { | ||
| 633 | // Only the focused output lights the focused window's lines. | 633 | // Only the focused output lights the focused window's lines. | ||
M internal/core/overview.go +40 -0
| @@ -625,6 +625,46 @@ func (m *Monitor) overviewLayout(result []Placement) []Placement { | |||
| 625 | 625 | return result | |
| 626 | 626 | } | |
| 627 | 627 | ||
| 628 | + | // overviewDividers uses final placements so rules cannot cross translated cards. | |
| 629 | + | func (m *Monitor) overviewDividers(layout []Placement) []ports.Separator { | |
| 630 | + | if m.Current().policy().workspace != horizontalAxis { | |
| 631 | + | _, lines := m.overviewRows() | |
| 632 | + | return lines | |
| 633 | + | } | |
| 634 | + | cur := m.Current() | |
| 635 | + | list := m.overviewWorkspaces() | |
| 636 | + | at := indexOf(list, cur) | |
| 637 | + | bounds := func(w *Workspace) (int, int) { | |
| 638 | + | lo, hi := int(^uint(0)>>1), -int(^uint(0)>>1) | |
| 639 | + | for _, p := range layout { | |
| 640 | + | owner, _ := m.find(p.ID) | |
| 641 | + | if owner == w && !p.Hidden { | |
| 642 | + | lo = min(lo, p.Rect.X) | |
| 643 | + | hi = max(hi, p.Rect.X+p.Rect.W) | |
| 644 | + | } | |
| 645 | + | } | |
| 646 | + | return lo, hi | |
| 647 | + | } | |
| 648 | + | left, right := bounds(cur) | |
| 649 | + | u := cur.overviewArea() | |
| 650 | + | var lines []ports.Separator | |
| 651 | + | for _, i := range []int{at - 1, at + 1} { | |
| 652 | + | if i < 0 || i >= len(list) || m.isHidden(list[i]) == m.isHidden(cur) { | |
| 653 | + | continue | |
| 654 | + | } | |
| 655 | + | lo, hi := bounds(list[i]) | |
| 656 | + | if lo > hi { | |
| 657 | + | continue | |
| 658 | + | } | |
| 659 | + | x := (right + lo) / 2 | |
| 660 | + | if i < at { | |
| 661 | + | x = (hi + left) / 2 | |
| 662 | + | } | |
| 663 | + | lines = append(lines, ports.Separator{Rect: Rect{X: x, Y: u.Y + u.H*4/100, W: 1, H: u.H * 92 / 100}}) | |
| 664 | + | } | |
| 665 | + | return lines | |
| 666 | + | } | |
| 667 | + | ||
| 628 | 668 | // fan places front and neighboring cards, farthest visible first and front | |
| 629 | 669 | // last. A card may contain several tiles; omitted cards stay in the layout | |
| 630 | 670 | // hidden so their clients are not left showing on screen. | |
| @@ -625,6 +625,46 @@ func (m *Monitor) overviewLayout(result []Placement) []Placement { | |||||
| 625 | return result | 625 | return result | ||
| 626 | } | 626 | } | ||
| 627 | 627 | ||||
| 628 | + | // overviewDividers uses final placements so rules cannot cross translated cards. | |||
| 629 | + | func (m *Monitor) overviewDividers(layout []Placement) []ports.Separator { | |||
| 630 | + | if m.Current().policy().workspace != horizontalAxis { | |||
| 631 | + | _, lines := m.overviewRows() | |||
| 632 | + | return lines | |||
| 633 | + | } | |||
| 634 | + | cur := m.Current() | |||
| 635 | + | list := m.overviewWorkspaces() | |||
| 636 | + | at := indexOf(list, cur) | |||
| 637 | + | bounds := func(w *Workspace) (int, int) { | |||
| 638 | + | lo, hi := int(^uint(0)>>1), -int(^uint(0)>>1) | |||
| 639 | + | for _, p := range layout { | |||
| 640 | + | owner, _ := m.find(p.ID) | |||
| 641 | + | if owner == w && !p.Hidden { | |||
| 642 | + | lo = min(lo, p.Rect.X) | |||
| 643 | + | hi = max(hi, p.Rect.X+p.Rect.W) | |||
| 644 | + | } | |||
| 645 | + | } | |||
| 646 | + | return lo, hi | |||
| 647 | + | } | |||
| 648 | + | left, right := bounds(cur) | |||
| 649 | + | u := cur.overviewArea() | |||
| 650 | + | var lines []ports.Separator | |||
| 651 | + | for _, i := range []int{at - 1, at + 1} { | |||
| 652 | + | if i < 0 || i >= len(list) || m.isHidden(list[i]) == m.isHidden(cur) { | |||
| 653 | + | continue | |||
| 654 | + | } | |||
| 655 | + | lo, hi := bounds(list[i]) | |||
| 656 | + | if lo > hi { | |||
| 657 | + | continue | |||
| 658 | + | } | |||
| 659 | + | x := (right + lo) / 2 | |||
| 660 | + | if i < at { | |||
| 661 | + | x = (hi + left) / 2 | |||
| 662 | + | } | |||
| 663 | + | lines = append(lines, ports.Separator{Rect: Rect{X: x, Y: u.Y + u.H*4/100, W: 1, H: u.H * 92 / 100}}) | |||
| 664 | + | } | |||
| 665 | + | return lines | |||
| 666 | + | } | |||
| 667 | + | ||||
| 628 | // fan places front and neighboring cards, farthest visible first and front | 668 | // fan places front and neighboring cards, farthest visible first and front | ||
| 629 | // last. A card may contain several tiles; omitted cards stay in the layout | 669 | // last. A card may contain several tiles; omitted cards stay in the layout | ||
| 630 | // hidden so their clients are not left showing on screen. | 670 | // hidden so their clients are not left showing on screen. | ||