Reimplement cursor as a query operation

This commit is contained in:
2020-04-10 20:54:58 +01:00
parent bb3ddc4896
commit f3fea83173
5 changed files with 58 additions and 37 deletions

View File

@@ -35,7 +35,7 @@ func main() {
log.Fatalf("Couldn't load menu %s: %v", *menuName, err) log.Fatalf("Couldn't load menu %s: %v", *menuName, err)
} }
driver, err := ui.NewDriver(menu) driver, err := ui.NewDriver(assets, menu)
if err != nil { if err != nil {
log.Fatalf("Couldn't initialize interface: %v", err) log.Fatalf("Couldn't initialize interface: %v", err)
} }
@@ -45,13 +45,6 @@ func main() {
log.Fatal("Couldn't create window: %v", err) log.Fatal("Couldn't create window: %v", err)
} }
// TODO: move this into driver. It will need to be able to change cursor.
cursor, err := assets.Cursor(assetstore.UltPointer)
if err != nil {
log.Fatalf("Couldn't load cursor: %v", err)
}
win.SetCursor(cursor.Image)
if err := win.Run(); err != nil { if err := win.Run(); err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@@ -114,7 +114,7 @@ func buildDriver(assets *assetstore.AssetStore, name driverName) (*ui.Driver, er
return nil, err return nil, err
} }
driver, err := ui.NewDriver(menu) driver, err := ui.NewDriver(assets, menu)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -138,6 +138,10 @@ func (f *Flow) Draw(screen *ebiten.Image) error {
return f.current.Draw(screen) return f.current.Draw(screen)
} }
func (f *Flow) Cursor() (*ebiten.Image, *ebiten.DrawImageOptions, error) {
return f.current.Cursor()
}
func (f *Flow) linkDrivers() { func (f *Flow) linkDrivers() {
// linkMain // linkMain
f.onClick(main, "2.1", f.setDriver(newGame)) // New game f.onClick(main, "2.1", f.setDriver(newGame)) // New game

View File

@@ -93,13 +93,6 @@ func Run(configFile string, overrideX, overrideY int) error {
return fmt.Errorf("Failed to create window: %v", err) return fmt.Errorf("Failed to create window: %v", err)
} }
// TODO: move this into driver. It will need to be able to change cursor.
cursor, err := assets.Cursor(assetstore.UltPointer)
if err != nil {
log.Fatalf("Couldn't load cursor: %v", err)
}
win.SetCursor(cursor.Image)
ordoor.win = win ordoor.win = win
if err := ordoor.setupFlow(); err != nil { if err := ordoor.setupFlow(); err != nil {
@@ -212,3 +205,11 @@ func (o *Ordoor) Draw(screen *ebiten.Image) error {
return fmt.Errorf("Unknown state: %v", o.state) return fmt.Errorf("Unknown state: %v", o.state)
} }
} }
func (o *Ordoor) Cursor() (*ebiten.Image, *ebiten.DrawImageOptions, error) {
if o.state == StateInterface {
return o.flow.Cursor()
}
return nil, nil, nil
}

View File

@@ -90,6 +90,7 @@ func registerBuilder(t menus.MenuType, f builderFunc) {
type Driver struct { type Driver struct {
Name string Name string
assets *assetstore.AssetStore
menu *assetstore.Menu menu *assetstore.Menu
// UI elements we need to drive // UI elements we need to drive
@@ -100,6 +101,8 @@ type Driver struct {
paintables []paintable paintables []paintable
valueables []valueable valueables []valueable
cursor assetstore.CursorName
// The cursor in two different coordinate spaces: original, and screen-scaled // The cursor in two different coordinate spaces: original, and screen-scaled
cursorOrig image.Point cursorOrig image.Point
cursorScaled image.Point cursorScaled image.Point
@@ -112,9 +115,11 @@ type Driver struct {
tooltip string tooltip string
} }
func NewDriver(menu *assetstore.Menu) (*Driver, error) { func NewDriver(assets *assetstore.AssetStore, menu *assetstore.Menu) (*Driver, error) {
driver := &Driver{ driver := &Driver{
Name: menu.Name, Name: menu.Name,
assets: assets,
menu: menu, menu: menu,
} }
@@ -307,6 +312,20 @@ func (d *Driver) Draw(screen *ebiten.Image) error {
return nil return nil
} }
func (d *Driver) Cursor() (*ebiten.Image, *ebiten.DrawImageOptions, error) {
cursor, err := d.assets.Cursor(d.cursor)
if err != nil {
return nil, nil, err
}
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(d.cursorOrig.X), float64(d.cursorOrig.Y))
op.GeoM.Concat(d.orig2native)
op.GeoM.Translate(float64(-cursor.Hotspot.X), float64(-cursor.Hotspot.Y))
return cursor.Image, op, nil
}
func (d *Driver) addRecord(record *menus.Record) error { func (d *Driver) addRecord(record *menus.Record) error {
//log.Printf("Adding record: %#+v", record) //log.Printf("Adding record: %#+v", record)
children := record.Children children := record.Children

View File

@@ -3,7 +3,6 @@ package ui
import ( import (
"flag" "flag"
"fmt" "fmt"
"image"
"log" "log"
"os" "os"
"runtime/debug" "runtime/debug"
@@ -19,6 +18,11 @@ type Game interface {
Draw(*ebiten.Image) error Draw(*ebiten.Image) error
} }
type CustomCursor interface {
// The cursor draw operation
Cursor() (*ebiten.Image, *ebiten.DrawImageOptions, error)
}
var ( var (
screenScale = flag.Float64("screen-scale", 1.0, "Scale the window by this factor") screenScale = flag.Float64("screen-scale", 1.0, "Scale the window by this factor")
cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
@@ -32,8 +36,6 @@ type Window struct {
KeyUpHandlers map[ebiten.Key]func() KeyUpHandlers map[ebiten.Key]func()
MouseWheelHandler func(float64, float64) MouseWheelHandler func(float64, float64)
cursor *ebiten.Image
// Allow the "game" to be switched out at any time // Allow the "game" to be switched out at any time
game Game game Game
@@ -74,15 +76,26 @@ func (w *Window) Layout(_, _ int) (int, int) {
return w.xRes, w.yRes return w.xRes, w.yRes
} }
func (w *Window) SetCursor(cursor *ebiten.Image) { func (w *Window) drawCursor(screen *ebiten.Image) error {
w.cursor = cursor cIface, ok := w.game.(CustomCursor)
if !ok {
return nil
}
cursor, op, err := cIface.Cursor()
if err != nil {
return err
}
// Hide the system cursor if we have a custom one // Hide the system cursor if we have a custom one
if cursor == nil { if cursor == nil {
ebiten.SetCursorMode(ebiten.CursorModeVisible) ebiten.SetCursorMode(ebiten.CursorModeVisible)
} else { return nil
ebiten.SetCursorMode(ebiten.CursorModeHidden)
} }
ebiten.SetCursorMode(ebiten.CursorModeHidden)
return screen.DrawImage(cursor, op)
} }
func (w *Window) Update(screen *ebiten.Image) (outErr error) { func (w *Window) Update(screen *ebiten.Image) (outErr error) {
@@ -125,23 +138,14 @@ func (w *Window) Update(screen *ebiten.Image) (outErr error) {
return err return err
} }
if w.cursor != nil {
// TODO: account for scaling, including the hotspot.
pos := image.Pt(ebiten.CursorPosition())
op := ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(pos.X), float64(pos.Y))
if err := screen.DrawImage(w.cursor, &op); err != nil {
return err
}
}
if w.debug { if w.debug {
// Draw FPS, etc, to the screen // Draw FPS, etc, to the screen
msg := fmt.Sprintf("tps=%0.2f fps=%0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS()) msg := fmt.Sprintf("tps=%0.2f fps=%0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS())
ebitenutil.DebugPrint(screen, msg) ebitenutil.DebugPrint(screen, msg)
} }
return nil // Draw the cursor last
return w.drawCursor(screen)
} }
// TODO: a stop or other cancellation mechanism // TODO: a stop or other cancellation mechanism