fix(window): normalize layout state before applying geometry
This commit is contained in:
parent
3cf69533bf
commit
a23e265cc6
3 changed files with 80 additions and 0 deletions
|
|
@ -436,10 +436,15 @@ func (s *Service) taskRestoreLayout(name string) error {
|
|||
if !found {
|
||||
continue
|
||||
}
|
||||
if pw.IsMaximised() || pw.IsMinimised() {
|
||||
pw.Restore()
|
||||
}
|
||||
pw.SetPosition(state.X, state.Y)
|
||||
pw.SetSize(state.Width, state.Height)
|
||||
if state.Maximized {
|
||||
pw.Maximise()
|
||||
} else {
|
||||
pw.Restore()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -274,6 +274,22 @@ func TestTaskTileWindows_UsesPrimaryScreenSize(t *testing.T) {
|
|||
assert.Equal(t, 1280, rightInfo.X)
|
||||
}
|
||||
|
||||
func TestTaskTileWindows_ResetsMaximizedState(t *testing.T) {
|
||||
_, c := newTestWindowServiceWithScreen(t)
|
||||
_, _, _ = c.PERFORM(TaskOpenWindow{Opts: []WindowOption{WithName("left")}})
|
||||
|
||||
_, _, _ = c.PERFORM(TaskMaximise{Name: "left"})
|
||||
_, handled, err := c.PERFORM(TaskTileWindows{Mode: "left-half", Windows: []string{"left"}})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, handled)
|
||||
|
||||
result, _, _ := c.QUERY(QueryWindowByName{Name: "left"})
|
||||
info := result.(*WindowInfo)
|
||||
assert.False(t, info.Maximized)
|
||||
assert.Equal(t, 0, info.X)
|
||||
assert.Equal(t, 1280, info.Width)
|
||||
}
|
||||
|
||||
func TestTaskSetOpacity_Good(t *testing.T) {
|
||||
_, c := newTestWindowService(t)
|
||||
_, _, _ = c.PERFORM(TaskOpenWindow{Opts: []WindowOption{WithName("test")}})
|
||||
|
|
@ -336,6 +352,28 @@ func TestTaskApplyWorkflow_Good(t *testing.T) {
|
|||
assert.Equal(t, editor.Width, assistant.X)
|
||||
}
|
||||
|
||||
func TestTaskRestoreLayout_ClearsMaximizedState(t *testing.T) {
|
||||
_, c := newTestWindowServiceWithScreen(t)
|
||||
_, _, _ = c.PERFORM(TaskOpenWindow{Opts: []WindowOption{WithName("editor")}})
|
||||
_, _, _ = c.PERFORM(TaskMaximise{Name: "editor"})
|
||||
|
||||
svc := core.MustServiceFor[*Service](c, "window")
|
||||
err := svc.Manager().Layout().SaveLayout("restore", map[string]WindowState{
|
||||
"editor": {X: 12, Y: 34, Width: 640, Height: 480, Maximized: false},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, handled, err := c.PERFORM(TaskRestoreLayout{Name: "restore"})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, handled)
|
||||
|
||||
result, _, _ := c.QUERY(QueryWindowByName{Name: "editor"})
|
||||
info := result.(*WindowInfo)
|
||||
assert.False(t, info.Maximized)
|
||||
assert.Equal(t, 12, info.X)
|
||||
assert.Equal(t, 640, info.Width)
|
||||
}
|
||||
|
||||
func TestTaskMaximise_Good(t *testing.T) {
|
||||
_, c := newTestWindowService(t)
|
||||
_, _, _ = c.PERFORM(TaskOpenWindow{Opts: []WindowOption{WithName("test")}})
|
||||
|
|
|
|||
|
|
@ -3,6 +3,18 @@ package window
|
|||
|
||||
import "fmt"
|
||||
|
||||
// normalizeWindowForLayout clears transient maximise/minimise state before
|
||||
// applying a new geometry. This keeps layout helpers effective even when a
|
||||
// window was previously maximised.
|
||||
func normalizeWindowForLayout(pw PlatformWindow) {
|
||||
if pw == nil {
|
||||
return
|
||||
}
|
||||
if pw.IsMaximised() || pw.IsMinimised() {
|
||||
pw.Restore()
|
||||
}
|
||||
}
|
||||
|
||||
// TileMode defines how windows are arranged.
|
||||
// Use: mode := window.TileModeLeftRight
|
||||
type TileMode int
|
||||
|
|
@ -99,6 +111,7 @@ func (m *Manager) TileWindows(mode TileMode, names []string, screenW, screenH in
|
|||
case TileModeLeftRight:
|
||||
w := screenW / len(windows)
|
||||
for i, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(i*w, 0)
|
||||
pw.SetSize(w, screenH)
|
||||
}
|
||||
|
|
@ -109,6 +122,7 @@ func (m *Manager) TileWindows(mode TileMode, names []string, screenW, screenH in
|
|||
}
|
||||
cellW := screenW / cols
|
||||
for i, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
row := i / cols
|
||||
col := i % cols
|
||||
rows := (len(windows) + cols - 1) / cols
|
||||
|
|
@ -118,41 +132,49 @@ func (m *Manager) TileWindows(mode TileMode, names []string, screenW, screenH in
|
|||
}
|
||||
case TileModeLeftHalf:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(halfW, screenH)
|
||||
}
|
||||
case TileModeRightHalf:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(halfW, 0)
|
||||
pw.SetSize(halfW, screenH)
|
||||
}
|
||||
case TileModeTopHalf:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(screenW, halfH)
|
||||
}
|
||||
case TileModeBottomHalf:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, halfH)
|
||||
pw.SetSize(screenW, halfH)
|
||||
}
|
||||
case TileModeTopLeft:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(halfW, halfH)
|
||||
}
|
||||
case TileModeTopRight:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(halfW, 0)
|
||||
pw.SetSize(halfW, halfH)
|
||||
}
|
||||
case TileModeBottomLeft:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, halfH)
|
||||
pw.SetSize(halfW, halfH)
|
||||
}
|
||||
case TileModeBottomRight:
|
||||
for _, pw := range windows {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(halfW, halfH)
|
||||
pw.SetSize(halfW, halfH)
|
||||
}
|
||||
|
|
@ -171,30 +193,39 @@ func (m *Manager) SnapWindow(name string, pos SnapPosition, screenW, screenH int
|
|||
|
||||
switch pos {
|
||||
case SnapLeft:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(halfW, screenH)
|
||||
case SnapRight:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(halfW, 0)
|
||||
pw.SetSize(halfW, screenH)
|
||||
case SnapTop:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(screenW, halfH)
|
||||
case SnapBottom:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, halfH)
|
||||
pw.SetSize(screenW, halfH)
|
||||
case SnapTopLeft:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(halfW, halfH)
|
||||
case SnapTopRight:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(halfW, 0)
|
||||
pw.SetSize(halfW, halfH)
|
||||
case SnapBottomLeft:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, halfH)
|
||||
pw.SetSize(halfW, halfH)
|
||||
case SnapBottomRight:
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(halfW, halfH)
|
||||
pw.SetSize(halfW, halfH)
|
||||
case SnapCenter:
|
||||
normalizeWindowForLayout(pw)
|
||||
cw, ch := pw.Size()
|
||||
pw.SetPosition((screenW-cw)/2, (screenH-ch)/2)
|
||||
}
|
||||
|
|
@ -208,6 +239,7 @@ func (m *Manager) StackWindows(names []string, offsetX, offsetY int) error {
|
|||
if !ok {
|
||||
return fmt.Errorf("window %q not found", name)
|
||||
}
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(i*offsetX, i*offsetY)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -224,11 +256,13 @@ func (m *Manager) ApplyWorkflow(workflow WorkflowLayout, names []string, screenW
|
|||
// 70/30 split — main editor + terminal
|
||||
mainW := screenW * 70 / 100
|
||||
if pw, ok := m.Get(names[0]); ok {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(mainW, screenH)
|
||||
}
|
||||
if len(names) > 1 {
|
||||
if pw, ok := m.Get(names[1]); ok {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(mainW, 0)
|
||||
pw.SetSize(screenW-mainW, screenH)
|
||||
}
|
||||
|
|
@ -237,11 +271,13 @@ func (m *Manager) ApplyWorkflow(workflow WorkflowLayout, names []string, screenW
|
|||
// 60/40 split
|
||||
mainW := screenW * 60 / 100
|
||||
if pw, ok := m.Get(names[0]); ok {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(mainW, screenH)
|
||||
}
|
||||
if len(names) > 1 {
|
||||
if pw, ok := m.Get(names[1]); ok {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(mainW, 0)
|
||||
pw.SetSize(screenW-mainW, screenH)
|
||||
}
|
||||
|
|
@ -249,6 +285,7 @@ func (m *Manager) ApplyWorkflow(workflow WorkflowLayout, names []string, screenW
|
|||
case WorkflowPresenting:
|
||||
// Maximise first window
|
||||
if pw, ok := m.Get(names[0]); ok {
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(0, 0)
|
||||
pw.SetSize(screenW, screenH)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue