From 9b2f864fc8bc6dd3a56c93da623ae47ad0dbe12d Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 30 Nov 2019 23:22:23 +0900 Subject: [PATCH] ui: Add SetWindowPosition(x, y int) Fixes #936 --- examples/windowsize/main.go | 76 +++++++++++++++++++++++++++------- internal/driver/ui.go | 1 + internal/uidriver/glfw/ui.go | 57 ++++++++++++++++++------- internal/uidriver/js/ui.go | 4 ++ internal/uidriver/mobile/ui.go | 4 ++ window.go | 11 ++++- 6 files changed, 122 insertions(+), 31 deletions(-) diff --git a/examples/windowsize/main.go b/examples/windowsize/main.go index b14188fcc..5e2b3f0ab 100644 --- a/examples/windowsize/main.go +++ b/examples/windowsize/main.go @@ -18,6 +18,7 @@ package main import ( "bytes" + "flag" "fmt" "image" "image/color" @@ -25,6 +26,8 @@ import ( "log" "math" "math/rand" + "strconv" + "strings" "time" "github.com/hajimehoshi/ebiten" @@ -33,7 +36,12 @@ import ( "github.com/hajimehoshi/ebiten/inpututil" ) +var ( + flagWindowPosition = flag.String("windowposition", "", "window position (e.g., 100,200)") +) + func init() { + flag.Parse() rand.Seed(time.Now().UnixNano()) } @@ -77,22 +85,38 @@ func update(screen *ebiten.Image) error { vsyncEnabled := ebiten.IsVsyncEnabled() tps := ebiten.MaxTPS() decorated := ebiten.IsWindowDecorated() + positionX, positionY := ebiten.WindowPosition() - if inpututil.IsKeyJustPressed(ebiten.KeyUp) { - screenHeight += d - } - if inpututil.IsKeyJustPressed(ebiten.KeyDown) { - if 16 < screenHeight && d < screenHeight { - screenHeight -= d + if ebiten.IsKeyPressed(ebiten.KeyShift) { + if inpututil.IsKeyJustPressed(ebiten.KeyUp) { + screenHeight += d } - } - if inpututil.IsKeyJustPressed(ebiten.KeyLeft) { - if 16 < screenWidth && d < screenWidth { - screenWidth -= d + if inpututil.IsKeyJustPressed(ebiten.KeyDown) { + if 16 < screenHeight && d < screenHeight { + screenHeight -= d + } + } + if inpututil.IsKeyJustPressed(ebiten.KeyLeft) { + if 16 < screenWidth && d < screenWidth { + screenWidth -= d + } + } + if inpututil.IsKeyJustPressed(ebiten.KeyRight) { + screenWidth += d + } + } else { + if inpututil.IsKeyJustPressed(ebiten.KeyUp) { + positionY -= 4 + } + if inpututil.IsKeyJustPressed(ebiten.KeyDown) { + positionY += 4 + } + if inpututil.IsKeyJustPressed(ebiten.KeyLeft) { + positionX -= 4 + } + if inpututil.IsKeyJustPressed(ebiten.KeyRight) { + positionX += 4 } - } - if inpututil.IsKeyJustPressed(ebiten.KeyRight) { - screenWidth += d } if inpututil.IsKeyJustPressed(ebiten.KeyS) { switch screenScale { @@ -146,6 +170,7 @@ func update(screen *ebiten.Image) error { ebiten.SetVsyncEnabled(vsyncEnabled) ebiten.SetMaxTPS(tps) ebiten.SetWindowDecorated(decorated) + ebiten.SetWindowPosition(positionX, positionY) if inpututil.IsKeyJustPressed(ebiten.KeyI) { ebiten.SetWindowIcon([]image.Image{createRandomIconImage()}) @@ -173,7 +198,7 @@ func update(screen *ebiten.Image) error { if t := ebiten.MaxTPS(); t != ebiten.UncappedTPS { tpsStr = fmt.Sprintf("%d", t) } - msg := fmt.Sprintf(`Press arrow keys to change the window size + msg := fmt.Sprintf(`Press shift + arrow keys to change the window size Press S key to change the window scale (only for desktops) Press F key to switch the fullscreen state (only for desktops) Press B key to switch the run-in-background state @@ -191,6 +216,25 @@ Device Scale Factor: %0.2f`, wx, wy, cx, cy, ebiten.CurrentTPS(), tpsStr, ebiten return nil } +func parseWindowPosition() (int, int, bool) { + if *flagWindowPosition == "" { + return 0, 0, false + } + tokens := strings.Split(*flagWindowPosition, ",") + if len(tokens) != 2 { + return 0, 0, false + } + x, err := strconv.Atoi(tokens[0]) + if err != nil { + return 0, 0, false + } + y, err := strconv.Atoi(tokens[1]) + if err != nil { + return 0, 0, false + } + return x, y, true +} + func main() { fmt.Printf("Device scale factor: %0.2f\n", ebiten.DeviceScaleFactor()) w, h := ebiten.ScreenSizeInFullscreen() @@ -213,6 +257,10 @@ func main() { ebiten.SetWindowIcon([]image.Image{createRandomIconImage()}) + if x, y, ok := parseWindowPosition(); ok { + ebiten.SetWindowPosition(x, y) + } + if err := ebiten.Run(update, initScreenWidth, initScreenHeight, initScreenScale, "Window Size (Ebiten Demo)"); err != nil { log.Fatal(err) } diff --git a/internal/driver/ui.go b/internal/driver/ui.go index 2e4f0f9f3..56fcdbb50 100644 --- a/internal/driver/ui.go +++ b/internal/driver/ui.go @@ -57,6 +57,7 @@ type UI interface { SetWindowIcon(iconImages []image.Image) SetWindowResizable(resizable bool) SetWindowTitle(title string) + SetWindowPosition(x, y int) Input() Input } diff --git a/internal/uidriver/glfw/ui.go b/internal/uidriver/glfw/ui.go index 98c311e9e..0bc53effd 100644 --- a/internal/uidriver/glfw/ui.go +++ b/internal/uidriver/glfw/ui.go @@ -36,15 +36,11 @@ import ( ) type UserInterface struct { - title string - window *glfw.Window - width int - windowWidth int - height int - initMonitor *glfw.Monitor - initFullscreenWidth int - initFullscreenHeight int - + title string + window *glfw.Window + width int + windowWidth int + height int scale float64 fullscreenScale float64 @@ -57,11 +53,16 @@ type UserInterface struct { lastActualScale float64 - initFullscreen bool - initCursorVisible bool - initWindowDecorated bool - initWindowResizable bool - initIconImages []image.Image + initMonitor *glfw.Monitor + initFullscreenWidth int + initFullscreenHeight int + initFullscreen bool + initCursorVisible bool + initWindowDecorated bool + initWindowResizable bool + initWindowPositionX *int + initWindowPositionY *int + initIconImages []image.Image reqWidth int reqHeight int @@ -667,8 +668,14 @@ func (u *UserInterface) run(width, height int, scale float64, title string, cont u.window.SetTitle(title) u.window.Show() - x := mx + (v.Width-w)/2 - y := my + (v.Height-h)/3 + x, y := 0, 0 + if u.initWindowPositionX != nil && u.initWindowPositionY != nil { + x = *u.initWindowPositionX + y = *u.initWindowPositionY + } else { + x = mx + (v.Width-w)/2 + y = my + (v.Height-h)/3 + } // Adjusting the position is needed only when the monitor is primary. (#829) if mx == 0 && my == 0 { x, y = adjustWindowPosition(x, y) @@ -997,6 +1004,24 @@ func (u *UserInterface) currentMonitor() *glfw.Monitor { return u.currentMonitorFromPosition() } +func (u *UserInterface) SetWindowPosition(x, y int) { + if !u.isRunning() { + if u.initWindowPositionX == nil { + u.initWindowPositionX = new(int) + } + if u.initWindowPositionY == nil { + u.initWindowPositionY = new(int) + } + *u.initWindowPositionX = x + *u.initWindowPositionY = y + return + } + _ = u.t.Call(func() error { + u.window.SetPos(x, y) + return nil + }) +} + func (u *UserInterface) WindowPosition() (int, int) { if !u.isRunning() { panic("ui: Run is not called yet") diff --git a/internal/uidriver/js/ui.go b/internal/uidriver/js/ui.go index cdc83b31c..7c81b38ef 100644 --- a/internal/uidriver/js/ui.go +++ b/internal/uidriver/js/ui.go @@ -479,6 +479,10 @@ func (u *UserInterface) updateScreenSize() { u.sizeChanged = true } +func (u *UserInterface) SetWindowPosition(x, y int) { + // Do nothing +} + func (u *UserInterface) WindowPosition() (int, int) { return 0, 0 } diff --git a/internal/uidriver/mobile/ui.go b/internal/uidriver/mobile/ui.go index 4c6776a27..2ea943675 100644 --- a/internal/uidriver/mobile/ui.go +++ b/internal/uidriver/mobile/ui.go @@ -443,6 +443,10 @@ func (u *UserInterface) DeviceScaleFactor() float64 { return deviceScale() } +func (u *UserInterface) SetWindowPosition(x, y int) { + // Do nothing +} + func (u *UserInterface) WindowPosition() (int, int) { return 0, 0 } diff --git a/window.go b/window.go index 496ae5517..95e11d3c0 100644 --- a/window.go +++ b/window.go @@ -100,6 +100,15 @@ func SetWindowIcon(iconImages []image.Image) { // WindowPosition panics before Run is called. // // WindowPosition returns (0, 0) on browsers and mobiles. -func WindowPosition() (int, int) { +func WindowPosition() (x, y int) { return uiDriver().WindowPosition() } + +// SetWindowPosition sets the window position. +// +// SetWindowPosition works before and after Run is called. +// +// SetWindowPosition does nothing on browsers and mobiles. +func SetWindowPosition(x, y int) { + uiDriver().SetWindowPosition(x, y) +}