ui: Add SetWindowResizable

This change also fixes example/windowsize.

Fixes #320
This commit is contained in:
Hajime Hoshi 2019-12-22 18:08:02 +09:00
parent 4aa80de34d
commit 049aa552d4
5 changed files with 96 additions and 28 deletions

View File

@ -50,11 +50,14 @@ var (
// * ebiten.RunGame
// * ebiten.SetWindowSize
// * ebiten.WindowSize
//
// A resizable window is available only when flagLegacy is false.
flagLegacy = flag.Bool("legacy", false, "use the legacy API")
flagFullscreen = flag.Bool("fullscreen", false, "fullscreen")
flagWindowPosition = flag.String("windowposition", "", "window position (e.g., 100,200)")
flagScreenTransparent = flag.Bool("screentransparent", false, "screen transparent")
flagAutoAdjusting = flag.Bool("autoadjusting", false, "make the game screen auto-adjusting")
)
func init() {
@ -98,6 +101,10 @@ type game struct {
}
func (g *game) Layout(outsideWidth, outsideHeight int) (int, int) {
if *flagAutoAdjusting {
g.width, g.height = outsideWidth, outsideHeight
return outsideWidth, outsideHeight
}
// Ignore the outside size. This means that the offscreen is not adjusted with the outside world.
return g.width, g.height
}
@ -114,9 +121,8 @@ func (g *game) Update(screen *ebiten.Image) error {
} else {
screenWidth = g.width
screenHeight = g.height
ww, _ := ebiten.WindowSize()
if ww > 0 {
screenScale = float64(ww) / float64(g.width)
if ww, wh := ebiten.WindowSize(); ww > 0 && wh > 0 {
screenScale = math.Min(float64(ww)/float64(g.width), float64(wh)/float64(g.height))
} else {
// ebiten.WindowSize can return (0, 0) on browsers or mobiles.
screenScale = 1
@ -131,24 +137,30 @@ func (g *game) Update(screen *ebiten.Image) error {
decorated := ebiten.IsWindowDecorated()
positionX, positionY := ebiten.WindowPosition()
transparent := ebiten.IsScreenTransparent()
resizable := ebiten.IsWindowResizable()
const d = 16
toUpdateWindowSize := false
if ebiten.IsKeyPressed(ebiten.KeyShift) {
if inpututil.IsKeyJustPressed(ebiten.KeyUp) {
screenHeight += d
toUpdateWindowSize = true
}
if inpututil.IsKeyJustPressed(ebiten.KeyDown) {
if 16 < screenHeight && d < screenHeight {
screenHeight -= d
toUpdateWindowSize = true
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyLeft) {
if 16 < screenWidth && d < screenWidth {
screenWidth -= d
toUpdateWindowSize = true
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyRight) {
screenWidth += d
toUpdateWindowSize = true
}
} else {
if inpututil.IsKeyJustPressed(ebiten.KeyUp) {
@ -164,19 +176,18 @@ func (g *game) Update(screen *ebiten.Image) error {
positionX += d
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyS) {
switch screenScale {
case 0.75:
if inpututil.IsKeyJustPressed(ebiten.KeyS) && !*flagAutoAdjusting {
switch {
case screenScale < 1:
screenScale = 1
case 1:
case screenScale < 1.5:
screenScale = 1.5
case 1.5:
case screenScale < 2:
screenScale = 2
case 2:
screenScale = 0.75
default:
panic("not reached")
screenScale = 0.75
}
toUpdateWindowSize = true
}
if inpututil.IsKeyJustPressed(ebiten.KeyF) {
fullscreen = !fullscreen
@ -207,7 +218,11 @@ func (g *game) Update(screen *ebiten.Image) error {
if inpututil.IsKeyJustPressed(ebiten.KeyD) {
decorated = !decorated
}
if inpututil.IsKeyJustPressed(ebiten.KeyR) {
resizable = !resizable
}
if toUpdateWindowSize {
if *flagLegacy {
ebiten.SetScreenSize(screenWidth, screenHeight)
ebiten.SetScreenScale(screenScale)
@ -216,6 +231,7 @@ func (g *game) Update(screen *ebiten.Image) error {
g.height = screenHeight
ebiten.SetWindowSize(int(float64(screenWidth)*screenScale), int(float64(screenHeight)*screenScale))
}
}
ebiten.SetFullscreen(fullscreen)
ebiten.SetRunnableInBackground(runnableInBackground)
ebiten.SetCursorVisible(cursorVisible)
@ -223,6 +239,10 @@ func (g *game) Update(screen *ebiten.Image) error {
ebiten.SetMaxTPS(tps)
ebiten.SetWindowDecorated(decorated)
ebiten.SetWindowPosition(positionX, positionY)
if !*flagLegacy {
// A resizable window is available only with RunGame.
ebiten.SetWindowResizable(resizable)
}
if inpututil.IsKeyJustPressed(ebiten.KeyI) {
ebiten.SetWindowIcon([]image.Image{createRandomIconImage()})
@ -252,21 +272,29 @@ func (g *game) Update(screen *ebiten.Image) error {
if t := ebiten.MaxTPS(); t != ebiten.UncappedTPS {
tpsStr = fmt.Sprintf("%d", t)
}
var msgS string
var msgR string
if *flagLegacy {
msgS = "Press S key to change the window scale (only for desktops)\n"
} else {
msgR = "Press R key to switch the window resizable state (only for desktops)\n"
}
msg := fmt.Sprintf(`Press arrow keys to move the window
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)
%sPress F key to switch the fullscreen state (only for desktops)
Press B key to switch the run-in-background state
Press C key to switch the cursor visibility
Press I key to change the window icon (only for desktops)
Press V key to switch vsync
Press T key to switch TPS (ticks per second)
Press D key to switch the window decoration
Windows Position: (%d, %d)
Press D key to switch the window decoration (only for desktops)
%sWindows Position: (%d, %d)
Cursor: (%d, %d)
TPS: Current: %0.2f / Max: %s
FPS: %0.2f
Device Scale Factor: %0.2f`, wx, wy, cx, cy, ebiten.CurrentTPS(), tpsStr, ebiten.CurrentFPS(), ebiten.DeviceScaleFactor())
Device Scale Factor: %0.2f`, msgS, msgR, wx, wy, cx, cy, ebiten.CurrentTPS(), tpsStr, ebiten.CurrentFPS(), ebiten.DeviceScaleFactor())
ebitenutil.DebugPrint(screen, msg)
return nil
}
@ -295,6 +323,10 @@ func main() {
w, h := ebiten.ScreenSizeInFullscreen()
fmt.Printf("Screen size in fullscreen: %d, %d\n", w, h)
if !*flagLegacy {
fmt.Println("Tip: With -autoadjusting flag, you can make an adjustable game screen.")
}
// Decode image from a byte slice instead of a file so that
// this example works in any working directory.
// If you want to use a file, there are some options:
@ -325,6 +357,12 @@ func main() {
if *flagFullscreen {
ebiten.SetFullscreen(true)
}
if *flagAutoAdjusting {
if *flagLegacy {
log.Println("-autoadjusting flag cannot work with -legacy flag")
}
ebiten.SetWindowResizable(true)
}
const title = "Window Size (Ebiten Demo)"
if *flagLegacy {

View File

@ -552,10 +552,14 @@ func (u *UserInterface) SetWindowResizable(resizable bool) {
u.setInitWindowResizable(resizable)
return
}
panic("glfw: SetWindowResizable can't be called after the main loop so far.")
// TODO: Now SetAttrib doesn't exist on GLFW 3.2. Revisit later (#556).
_ = u.t.Call(func() error {
v := glfw.False
if resizable {
v = glfw.True
}
u.window.SetAttrib(glfw.Resizable, v)
return nil
})
}
func (u *UserInterface) DeviceScaleFactor() float64 {

3
run.go
View File

@ -153,6 +153,9 @@ func IsRunningSlowly() bool {
//
// Don't call Run twice or more in one process.
func Run(f func(*Image) error, width, height int, scale float64, title string) error {
if IsWindowResizable() {
panic("ebiten: a resizable window works with RunGame, not Run")
}
game := &defaultGame{
update: (&imageDumper{f: f}).update,
width: width,

View File

@ -184,6 +184,18 @@ func (c *uiContext) updateOffscreen() {
// scale. This is fine since ebiten.ScreenScale will be deprecated.
}
func (c *uiContext) setWindowResizable(resizable bool) {
c.m.Lock()
defer c.m.Unlock()
if resizable && c.game != nil {
if _, ok := c.game.(*defaultGame); ok {
panic("ebiten: a resizable window works with RunGame, not Run")
}
}
uiDriver().SetWindowResizable(resizable)
}
func (c *uiContext) screenScale() float64 {
if c.offscreen == nil {
return 0

View File

@ -62,13 +62,24 @@ func setWindowResizable(resizable bool) {
uiDriver().SetWindowResizable(resizable)
}
// IsWindowResizable reports whether the window is resizable.
// IsWindowResizable reports whether the window is resizable by the user's dragging on desktops.
// On the other environments, IsWindowResizable always returns false.
//
// IsWindowResizable is concurrent-safe.
func IsWindowResizable() bool {
return uiDriver().IsWindowResizable()
}
// SetWindowResizable sets whether the window is resizable by the user's dragging on desktops.
// On the other environments, SetWindowResizable does nothing.
//
// If SetWindowResizable is called with true and Run is used, SetWindowResizable panics. Use RunGame instead.
//
// SetWindowResizable is concurrent-safe.
func SetWindowResizable(resizable bool) {
theUIContext.setWindowResizable(resizable)
}
// SetWindowTitle sets the title of the window.
//
// SetWindowTitle does nothing on mobiles.