feat(gui): add missing window mutators and MCP tools
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
57fb567a68
commit
a07fa49c20
7 changed files with 237 additions and 44 deletions
|
|
@ -1243,13 +1243,15 @@ func (s *Service) GetSavedWindowStates() map[string]window.WindowState {
|
|||
|
||||
// CreateWindowOptions contains options for creating a new window.
|
||||
type CreateWindowOptions struct {
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
X int `json:"x,omitempty"`
|
||||
Y int `json:"y,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
X int `json:"x,omitempty"`
|
||||
Y int `json:"y,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
AlwaysOnTop bool `json:"alwaysOnTop,omitempty"`
|
||||
BackgroundColour [4]uint8 `json:"backgroundColour,omitempty"`
|
||||
}
|
||||
|
||||
// CreateWindow creates a new window with the specified options.
|
||||
|
|
@ -1258,12 +1260,16 @@ func (s *Service) CreateWindow(opts CreateWindowOptions) (*window.WindowInfo, er
|
|||
return nil, fmt.Errorf("window name is required")
|
||||
}
|
||||
result, _, err := s.Core().PERFORM(window.TaskOpenWindow{
|
||||
Opts: []window.WindowOption{
|
||||
window.WithName(opts.Name),
|
||||
window.WithTitle(opts.Title),
|
||||
window.WithURL(opts.URL),
|
||||
window.WithSize(opts.Width, opts.Height),
|
||||
window.WithPosition(opts.X, opts.Y),
|
||||
Window: &window.Window{
|
||||
Name: opts.Name,
|
||||
Title: opts.Title,
|
||||
URL: opts.URL,
|
||||
X: opts.X,
|
||||
Y: opts.Y,
|
||||
Width: opts.Width,
|
||||
Height: opts.Height,
|
||||
AlwaysOnTop: opts.AlwaysOnTop,
|
||||
BackgroundColour: opts.BackgroundColour,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -89,22 +89,17 @@ type WindowCreateOutput struct {
|
|||
}
|
||||
|
||||
func (s *Subsystem) windowCreate(_ context.Context, _ *mcp.CallToolRequest, input WindowCreateInput) (*mcp.CallToolResult, WindowCreateOutput, error) {
|
||||
opts := []window.WindowOption{
|
||||
window.WithName(input.Name),
|
||||
}
|
||||
if input.Title != "" {
|
||||
opts = append(opts, window.WithTitle(input.Title))
|
||||
}
|
||||
if input.URL != "" {
|
||||
opts = append(opts, window.WithURL(input.URL))
|
||||
}
|
||||
if input.Width > 0 || input.Height > 0 {
|
||||
opts = append(opts, window.WithSize(input.Width, input.Height))
|
||||
}
|
||||
if input.X != 0 || input.Y != 0 {
|
||||
opts = append(opts, window.WithPosition(input.X, input.Y))
|
||||
}
|
||||
result, _, err := s.core.PERFORM(window.TaskOpenWindow{Opts: opts})
|
||||
result, _, err := s.core.PERFORM(window.TaskOpenWindow{
|
||||
Window: &window.Window{
|
||||
Name: input.Name,
|
||||
Title: input.Title,
|
||||
URL: input.URL,
|
||||
Width: input.Width,
|
||||
Height: input.Height,
|
||||
X: input.X,
|
||||
Y: input.Y,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, WindowCreateOutput{}, err
|
||||
}
|
||||
|
|
@ -163,7 +158,7 @@ type WindowSizeOutput struct {
|
|||
}
|
||||
|
||||
func (s *Subsystem) windowSize(_ context.Context, _ *mcp.CallToolRequest, input WindowSizeInput) (*mcp.CallToolResult, WindowSizeOutput, error) {
|
||||
_, _, err := s.core.PERFORM(window.TaskSetSize{Name: input.Name, W: input.Width, H: input.Height})
|
||||
_, _, err := s.core.PERFORM(window.TaskSetSize{Name: input.Name, Width: input.Width, Height: input.Height})
|
||||
if err != nil {
|
||||
return nil, WindowSizeOutput{}, err
|
||||
}
|
||||
|
|
@ -188,7 +183,7 @@ func (s *Subsystem) windowBounds(_ context.Context, _ *mcp.CallToolRequest, inpu
|
|||
if err != nil {
|
||||
return nil, WindowBoundsOutput{}, err
|
||||
}
|
||||
_, _, err = s.core.PERFORM(window.TaskSetSize{Name: input.Name, W: input.Width, H: input.Height})
|
||||
_, _, err = s.core.PERFORM(window.TaskSetSize{Name: input.Name, Width: input.Width, Height: input.Height})
|
||||
if err != nil {
|
||||
return nil, WindowBoundsOutput{}, err
|
||||
}
|
||||
|
|
@ -281,6 +276,27 @@ func (s *Subsystem) windowTitle(_ context.Context, _ *mcp.CallToolRequest, input
|
|||
return nil, WindowTitleOutput{Success: true}, nil
|
||||
}
|
||||
|
||||
// --- window_title_get ---
|
||||
|
||||
type WindowTitleGetInput struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type WindowTitleGetOutput struct {
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
func (s *Subsystem) windowTitleGet(_ context.Context, _ *mcp.CallToolRequest, input WindowTitleGetInput) (*mcp.CallToolResult, WindowTitleGetOutput, error) {
|
||||
result, _, err := s.core.QUERY(window.QueryWindowByName{Name: input.Name})
|
||||
if err != nil {
|
||||
return nil, WindowTitleGetOutput{}, err
|
||||
}
|
||||
info, _ := result.(*window.WindowInfo)
|
||||
if info == nil {
|
||||
return nil, WindowTitleGetOutput{}, nil
|
||||
}
|
||||
return nil, WindowTitleGetOutput{Title: info.Title}, nil
|
||||
}
|
||||
|
||||
// --- window_visibility ---
|
||||
|
||||
type WindowVisibilityInput struct {
|
||||
|
|
@ -299,6 +315,47 @@ func (s *Subsystem) windowVisibility(_ context.Context, _ *mcp.CallToolRequest,
|
|||
return nil, WindowVisibilityOutput{Success: true}, nil
|
||||
}
|
||||
|
||||
// --- window_always_on_top ---
|
||||
|
||||
type WindowAlwaysOnTopInput struct {
|
||||
Name string `json:"name"`
|
||||
AlwaysOnTop bool `json:"alwaysOnTop"`
|
||||
}
|
||||
type WindowAlwaysOnTopOutput struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
func (s *Subsystem) windowAlwaysOnTop(_ context.Context, _ *mcp.CallToolRequest, input WindowAlwaysOnTopInput) (*mcp.CallToolResult, WindowAlwaysOnTopOutput, error) {
|
||||
_, _, err := s.core.PERFORM(window.TaskSetAlwaysOnTop{Name: input.Name, AlwaysOnTop: input.AlwaysOnTop})
|
||||
if err != nil {
|
||||
return nil, WindowAlwaysOnTopOutput{}, err
|
||||
}
|
||||
return nil, WindowAlwaysOnTopOutput{Success: true}, nil
|
||||
}
|
||||
|
||||
// --- window_background_colour ---
|
||||
|
||||
type WindowBackgroundColourInput struct {
|
||||
Name string `json:"name"`
|
||||
Red uint8 `json:"red"`
|
||||
Green uint8 `json:"green"`
|
||||
Blue uint8 `json:"blue"`
|
||||
Alpha uint8 `json:"alpha"`
|
||||
}
|
||||
type WindowBackgroundColourOutput struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
func (s *Subsystem) windowBackgroundColour(_ context.Context, _ *mcp.CallToolRequest, input WindowBackgroundColourInput) (*mcp.CallToolResult, WindowBackgroundColourOutput, error) {
|
||||
_, _, err := s.core.PERFORM(window.TaskSetBackgroundColour{
|
||||
Name: input.Name, Red: input.Red, Green: input.Green, Blue: input.Blue, Alpha: input.Alpha,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, WindowBackgroundColourOutput{}, err
|
||||
}
|
||||
return nil, WindowBackgroundColourOutput{Success: true}, nil
|
||||
}
|
||||
|
||||
// --- window_fullscreen ---
|
||||
|
||||
type WindowFullscreenInput struct {
|
||||
|
|
@ -333,6 +390,9 @@ func (s *Subsystem) registerWindowTools(server *mcp.Server) {
|
|||
mcp.AddTool(server, &mcp.Tool{Name: "window_restore", Description: "Restore a maximised or minimised window"}, s.windowRestore)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "window_focus", Description: "Bring a window to the front"}, s.windowFocus)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "window_title", Description: "Set the title of a window"}, s.windowTitle)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "window_title_get", Description: "Get the title of a window"}, s.windowTitleGet)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "window_visibility", Description: "Show or hide a window"}, s.windowVisibility)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "window_always_on_top", Description: "Pin a window above others"}, s.windowAlwaysOnTop)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "window_background_colour", Description: "Set a window background colour"}, s.windowBackgroundColour)
|
||||
mcp.AddTool(server, &mcp.Tool{Name: "window_fullscreen", Description: "Set a window to fullscreen mode"}, s.windowFullscreen)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,14 @@ type WindowInfo struct {
|
|||
Focused bool `json:"focused"`
|
||||
}
|
||||
|
||||
// Bounds describes the position and size of a window.
|
||||
type Bounds struct {
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
}
|
||||
|
||||
// --- Queries (read-only) ---
|
||||
|
||||
// QueryWindowList returns all tracked windows. Result: []WindowInfo
|
||||
|
|
@ -24,6 +32,9 @@ type QueryWindowByName struct{ Name string }
|
|||
// Result: map[string]any
|
||||
type QueryConfig struct{}
|
||||
|
||||
// QueryWindowBounds returns the current bounds for a window.
|
||||
type QueryWindowBounds struct{ Name string }
|
||||
|
||||
// QueryFindSpace returns a suggested free placement for a new window.
|
||||
type QueryFindSpace struct {
|
||||
Width int
|
||||
|
|
@ -40,7 +51,10 @@ type QueryLayoutSuggestion struct {
|
|||
// --- Tasks (side-effects) ---
|
||||
|
||||
// TaskOpenWindow creates a new window. Result: WindowInfo
|
||||
type TaskOpenWindow struct{ Opts []WindowOption }
|
||||
type TaskOpenWindow struct {
|
||||
Window *Window
|
||||
Opts []WindowOption
|
||||
}
|
||||
|
||||
// TaskCloseWindow closes a window. Handler persists state BEFORE emitting ActionWindowClosed.
|
||||
type TaskCloseWindow struct{ Name string }
|
||||
|
|
@ -53,8 +67,9 @@ type TaskSetPosition struct {
|
|||
|
||||
// TaskSetSize resizes a window.
|
||||
type TaskSetSize struct {
|
||||
Name string
|
||||
W, H int
|
||||
Name string
|
||||
Width, Height int
|
||||
W, H int
|
||||
}
|
||||
|
||||
// TaskMaximise maximises a window.
|
||||
|
|
@ -75,6 +90,21 @@ type TaskSetTitle struct {
|
|||
Title string
|
||||
}
|
||||
|
||||
// TaskSetAlwaysOnTop pins a window above others.
|
||||
type TaskSetAlwaysOnTop struct {
|
||||
Name string
|
||||
AlwaysOnTop bool
|
||||
}
|
||||
|
||||
// TaskSetBackgroundColour updates the window background colour.
|
||||
type TaskSetBackgroundColour struct {
|
||||
Name string
|
||||
Red uint8
|
||||
Green uint8
|
||||
Blue uint8
|
||||
Alpha uint8
|
||||
}
|
||||
|
||||
// TaskSetVisibility shows or hides a window.
|
||||
type TaskSetVisibility struct {
|
||||
Name string
|
||||
|
|
@ -157,8 +187,9 @@ type ActionWindowMoved struct {
|
|||
}
|
||||
|
||||
type ActionWindowResized struct {
|
||||
Name string
|
||||
W, H int
|
||||
Name string
|
||||
Width, Height int
|
||||
W, H int
|
||||
}
|
||||
|
||||
type ActionWindowFocused struct{ Name string }
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ func (m *MockPlatform) CreateWindow(opts PlatformWindowOptions) PlatformWindow {
|
|||
name: opts.Name, title: opts.Title, url: opts.URL,
|
||||
width: opts.Width, height: opts.Height,
|
||||
x: opts.X, y: opts.Y,
|
||||
alwaysOnTop: opts.AlwaysOnTop,
|
||||
backgroundColor: opts.BackgroundColour,
|
||||
visible: !opts.Hidden,
|
||||
}
|
||||
m.Windows = append(m.Windows, w)
|
||||
return w
|
||||
|
|
@ -33,6 +36,7 @@ type MockWindow struct {
|
|||
width, height, x, y int
|
||||
maximised, focused bool
|
||||
visible, alwaysOnTop bool
|
||||
backgroundColor [4]uint8
|
||||
closed bool
|
||||
eventHandlers []func(WindowEvent)
|
||||
fileDropHandlers []func(paths []string, targetID string)
|
||||
|
|
@ -47,7 +51,7 @@ func (w *MockWindow) IsFocused() bool { return w.focused }
|
|||
func (w *MockWindow) SetTitle(title string) { w.title = title }
|
||||
func (w *MockWindow) SetPosition(x, y int) { w.x = x; w.y = y }
|
||||
func (w *MockWindow) SetSize(width, height int) { w.width = width; w.height = height }
|
||||
func (w *MockWindow) SetBackgroundColour(r, g, b, a uint8) {}
|
||||
func (w *MockWindow) SetBackgroundColour(r, g, b, a uint8) { w.backgroundColor = [4]uint8{r, g, b, a} }
|
||||
func (w *MockWindow) SetVisibility(visible bool) { w.visible = visible }
|
||||
func (w *MockWindow) SetAlwaysOnTop(alwaysOnTop bool) { w.alwaysOnTop = alwaysOnTop }
|
||||
func (w *MockWindow) Maximise() { w.maximised = true }
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ func (m *mockPlatform) CreateWindow(opts PlatformWindowOptions) PlatformWindow {
|
|||
name: opts.Name, title: opts.Title, url: opts.URL,
|
||||
width: opts.Width, height: opts.Height,
|
||||
x: opts.X, y: opts.Y,
|
||||
alwaysOnTop: opts.AlwaysOnTop,
|
||||
backgroundColor: opts.BackgroundColour,
|
||||
visible: !opts.Hidden,
|
||||
}
|
||||
m.windows = append(m.windows, w)
|
||||
return w
|
||||
|
|
@ -32,6 +35,7 @@ type mockWindow struct {
|
|||
width, height, x, y int
|
||||
maximised, focused bool
|
||||
visible, alwaysOnTop bool
|
||||
backgroundColor [4]uint8
|
||||
closed bool
|
||||
eventHandlers []func(WindowEvent)
|
||||
fileDropHandlers []func(paths []string, targetID string)
|
||||
|
|
@ -46,7 +50,7 @@ func (w *mockWindow) IsFocused() bool { return w.focused }
|
|||
func (w *mockWindow) SetTitle(title string) { w.title = title }
|
||||
func (w *mockWindow) SetPosition(x, y int) { w.x = x; w.y = y }
|
||||
func (w *mockWindow) SetSize(width, height int) { w.width = width; w.height = height }
|
||||
func (w *mockWindow) SetBackgroundColour(r, g, b, a uint8) {}
|
||||
func (w *mockWindow) SetBackgroundColour(r, g, b, a uint8) { w.backgroundColor = [4]uint8{r, g, b, a} }
|
||||
func (w *mockWindow) SetVisibility(visible bool) { w.visible = visible }
|
||||
func (w *mockWindow) SetAlwaysOnTop(alwaysOnTop bool) { w.alwaysOnTop = alwaysOnTop }
|
||||
func (w *mockWindow) Maximise() { w.maximised = true }
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ func (s *Service) handleQuery(c *core.Core, q core.Query) (any, bool, error) {
|
|||
return s.queryWindowList(), true, nil
|
||||
case QueryWindowByName:
|
||||
return s.queryWindowByName(q.Name), true, nil
|
||||
case QueryWindowBounds:
|
||||
if info := s.queryWindowByName(q.Name); info != nil {
|
||||
return &Bounds{X: info.X, Y: info.Y, Width: info.Width, Height: info.Height}, true, nil
|
||||
}
|
||||
return (*Bounds)(nil), true, nil
|
||||
case QueryLayoutList:
|
||||
return s.manager.Layout().ListLayouts(), true, nil
|
||||
case QueryLayoutGet:
|
||||
|
|
@ -131,7 +136,7 @@ func (s *Service) handleTask(c *core.Core, t core.Task) (any, bool, error) {
|
|||
case TaskSetPosition:
|
||||
return nil, true, s.taskSetPosition(t.Name, t.X, t.Y)
|
||||
case TaskSetSize:
|
||||
return nil, true, s.taskSetSize(t.Name, t.W, t.H)
|
||||
return nil, true, s.taskSetSize(t.Name, t.Width, t.Height, t.W, t.H)
|
||||
case TaskMaximise:
|
||||
return nil, true, s.taskMaximise(t.Name)
|
||||
case TaskMinimise:
|
||||
|
|
@ -142,6 +147,10 @@ func (s *Service) handleTask(c *core.Core, t core.Task) (any, bool, error) {
|
|||
return nil, true, s.taskRestore(t.Name)
|
||||
case TaskSetTitle:
|
||||
return nil, true, s.taskSetTitle(t.Name, t.Title)
|
||||
case TaskSetAlwaysOnTop:
|
||||
return nil, true, s.taskSetAlwaysOnTop(t.Name, t.AlwaysOnTop)
|
||||
case TaskSetBackgroundColour:
|
||||
return nil, true, s.taskSetBackgroundColour(t.Name, t.Red, t.Green, t.Blue, t.Alpha)
|
||||
case TaskSetVisibility:
|
||||
return nil, true, s.taskSetVisibility(t.Name, t.Visible)
|
||||
case TaskFullscreen:
|
||||
|
|
@ -171,7 +180,16 @@ func (s *Service) handleTask(c *core.Core, t core.Task) (any, bool, error) {
|
|||
}
|
||||
|
||||
func (s *Service) taskOpenWindow(t TaskOpenWindow) (any, bool, error) {
|
||||
pw, err := s.manager.Open(t.Opts...)
|
||||
var (
|
||||
pw PlatformWindow
|
||||
err error
|
||||
)
|
||||
if t.Window != nil {
|
||||
spec := *t.Window
|
||||
pw, err = s.manager.Create(&spec)
|
||||
} else {
|
||||
pw, err = s.manager.Open(t.Opts...)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
|
|
@ -205,7 +223,7 @@ func (s *Service) trackWindow(pw PlatformWindow) {
|
|||
if data := e.Data; data != nil {
|
||||
w, _ := data["w"].(int)
|
||||
h, _ := data["h"].(int)
|
||||
_ = s.Core().ACTION(ActionWindowResized{Name: e.Name, W: w, H: h})
|
||||
_ = s.Core().ACTION(ActionWindowResized{Name: e.Name, Width: w, Height: h, W: w, H: h})
|
||||
}
|
||||
case "close":
|
||||
_ = s.Core().ACTION(ActionWindowClosed{Name: e.Name})
|
||||
|
|
@ -243,13 +261,23 @@ func (s *Service) taskSetPosition(name string, x, y int) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) taskSetSize(name string, w, h int) error {
|
||||
func (s *Service) taskSetSize(name string, width, height, legacyWidth, legacyHeight int) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
}
|
||||
pw.SetSize(w, h)
|
||||
s.manager.State().UpdateSize(name, w, h)
|
||||
if width == 0 && height == 0 {
|
||||
width, height = legacyWidth, legacyHeight
|
||||
} else {
|
||||
if width == 0 {
|
||||
width = legacyWidth
|
||||
}
|
||||
if height == 0 {
|
||||
height = legacyHeight
|
||||
}
|
||||
}
|
||||
pw.SetSize(width, height)
|
||||
s.manager.State().UpdateSize(name, width, height)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -300,6 +328,24 @@ func (s *Service) taskSetTitle(name, title string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) taskSetAlwaysOnTop(name string, alwaysOnTop bool) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
}
|
||||
pw.SetAlwaysOnTop(alwaysOnTop)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) taskSetBackgroundColour(name string, red, green, blue, alpha uint8) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
}
|
||||
pw.SetBackgroundColour(red, green, blue, alpha)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) taskSetVisibility(name string, visible bool) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,18 @@ func TestTaskOpenWindow_Good(t *testing.T) {
|
|||
assert.Equal(t, "test", info.Name)
|
||||
}
|
||||
|
||||
func TestTaskOpenWindowDescriptor_Good(t *testing.T) {
|
||||
_, c := newTestWindowService(t)
|
||||
result, handled, err := c.PERFORM(TaskOpenWindow{
|
||||
Window: &Window{Name: "descriptor", Title: "Descriptor", Width: 640, Height: 480},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, handled)
|
||||
info := result.(WindowInfo)
|
||||
assert.Equal(t, "descriptor", info.Name)
|
||||
assert.Equal(t, "Descriptor", info.Title)
|
||||
}
|
||||
|
||||
func TestTaskOpenWindow_Bad(t *testing.T) {
|
||||
// No window service registered — PERFORM returns handled=false
|
||||
c, err := core.New(core.WithServiceLock())
|
||||
|
|
@ -141,6 +153,36 @@ func TestTaskSetSize_Good(t *testing.T) {
|
|||
assert.Equal(t, 600, info.Height)
|
||||
}
|
||||
|
||||
func TestTaskSetAlwaysOnTop_Good(t *testing.T) {
|
||||
_, c := newTestWindowService(t)
|
||||
_, _, _ = c.PERFORM(TaskOpenWindow{Opts: []WindowOption{WithName("test")}})
|
||||
|
||||
_, handled, err := c.PERFORM(TaskSetAlwaysOnTop{Name: "test", AlwaysOnTop: true})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, handled)
|
||||
|
||||
svc := core.MustServiceFor[*Service](c, "window")
|
||||
pw, ok := svc.Manager().Get("test")
|
||||
require.True(t, ok)
|
||||
assert.True(t, pw.(*mockWindow).alwaysOnTop)
|
||||
}
|
||||
|
||||
func TestTaskSetBackgroundColour_Good(t *testing.T) {
|
||||
_, c := newTestWindowService(t)
|
||||
_, _, _ = c.PERFORM(TaskOpenWindow{Opts: []WindowOption{WithName("test")}})
|
||||
|
||||
_, handled, err := c.PERFORM(TaskSetBackgroundColour{
|
||||
Name: "test", Red: 10, Green: 20, Blue: 30, Alpha: 40,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, handled)
|
||||
|
||||
svc := core.MustServiceFor[*Service](c, "window")
|
||||
pw, ok := svc.Manager().Get("test")
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, [4]uint8{10, 20, 30, 40}, pw.(*mockWindow).backgroundColor)
|
||||
}
|
||||
|
||||
func TestTaskStackWindows_Good(t *testing.T) {
|
||||
_, c := newTestWindowService(t)
|
||||
_, _, _ = c.PERFORM(TaskOpenWindow{Opts: []WindowOption{WithName("one")}})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue