package ui import ( "image" "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/ebitenutil" "code.ur.gs/lupine/ordoor/internal/menus" ) func init() { registerBuilder(menus.TypeStatic, registerStatic) registerBuilder(menus.TypeHypertext, registerHypertext) registerBuilder(menus.TypeOverlay, registerOverlay) registerBuilder(menus.TypeAnimationSample, registerAnimation) } // A non-interactive element is not a widget; it merely displays some pixels and // may optionally have a tooltip for display within bounds. // // For non-animated non-interactive elements, just give them a single frame. type noninteractive struct { frames animation rect image.Rectangle // Some non-interactives, e.g., overlays, are an image + text to be shown textImg *ebiten.Image hoverImpl } func registerStatic(d *Driver, r *menus.Record) error { // FIXME: SpriteID takes precedence over SHARE if present, but is that right? spriteId := r.Share if len(r.SpriteId) > 0 && r.SpriteId[0] != -1 { spriteId = r.SpriteId[0] } sprite, err := d.menu.Sprite(spriteId) if err != nil { return err } ni := &noninteractive{ frames: animation{sprite.Image}, hoverImpl: hoverImpl{text: r.Text}, rect: sprite.Rect, } d.hoverables = append(d.hoverables, ni) d.paintables = append(d.paintables, ni) return nil } func registerHypertext(d *Driver, r *menus.Record) error { sprite, err := d.menu.Sprite(r.Share) if err != nil { return err } ni := &noninteractive{ hoverImpl: hoverImpl{text: r.Text}, rect: sprite.Rect, } d.hoverables = append(d.hoverables, ni) return nil } // An overlay is a static image + some text that needs to be rendered func registerOverlay(d *Driver, r *menus.Record) error { sprite, err := d.menu.Sprite(r.Share) if err != nil { return err } ni := &noninteractive{ frames: animation{sprite.Image}, rect: sprite.Rect, } if r.Text != "" { // FIXME: we should be rendering the text much more nicely than this textImg, err := ebiten.NewImage(sprite.Rect.Dx(), sprite.Rect.Dy(), ebiten.FilterDefault) if err != nil { return err } ebitenutil.DebugPrint(textImg, r.Text) ni.textImg = textImg } d.paintables = append(d.paintables, ni) return nil } // An animation is a non-interactive element that displays something in a loop func registerAnimation(d *Driver, r *menus.Record) error { sprite, err := d.menu.Sprite(r.SpriteId[0]) if err != nil { return err } frames, err := d.menu.Images(r.SpriteId[0], r.DrawType) if err != nil { return err } ani := &noninteractive{ frames: animation(frames), hoverImpl: hoverImpl{text: r.Text}, rect: sprite.Rect, } d.hoverables = append(d.hoverables, ani) d.paintables = append(d.paintables, ani) return nil } func (n *noninteractive) bounds() image.Rectangle { return n.rect } func (n *noninteractive) regions(tick int) []region { out := oneRegion(n.bounds().Min, n.frames.image(tick)) if n.textImg != nil { out = append(out, oneRegion(n.bounds().Min, n.textImg)...) } return out }