2020-03-23 00:33:29 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
2020-03-24 20:21:55 +00:00
|
|
|
|
2020-03-26 22:09:26 +00:00
|
|
|
"github.com/hajimehoshi/ebiten"
|
|
|
|
"github.com/hajimehoshi/ebiten/ebitenutil"
|
|
|
|
|
2020-03-24 20:21:55 +00:00
|
|
|
"code.ur.gs/lupine/ordoor/internal/menus"
|
2020-03-23 00:33:29 +00:00
|
|
|
)
|
|
|
|
|
2020-03-24 20:21:55 +00:00
|
|
|
func init() {
|
|
|
|
registerBuilder(menus.TypeStatic, registerStatic)
|
|
|
|
registerBuilder(menus.TypeHypertext, registerHypertext)
|
2020-03-26 22:09:26 +00:00
|
|
|
registerBuilder(menus.TypeOverlay, registerOverlay)
|
2020-03-24 20:21:55 +00:00
|
|
|
registerBuilder(menus.TypeAnimationSample, registerAnimation)
|
|
|
|
}
|
|
|
|
|
2020-03-23 00:33:29 +00:00
|
|
|
// 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 {
|
2020-03-24 20:21:55 +00:00
|
|
|
frames animation
|
|
|
|
rect image.Rectangle
|
|
|
|
|
2020-03-26 22:09:26 +00:00
|
|
|
// Some non-interactives, e.g., overlays, are an image + text to be shown
|
|
|
|
textImg *ebiten.Image
|
|
|
|
|
2020-03-24 20:21:55 +00:00
|
|
|
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},
|
2020-03-26 22:09:26 +00:00
|
|
|
hoverImpl: hoverImpl{text: r.Text},
|
2020-03-24 20:21:55 +00:00
|
|
|
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{
|
2020-03-26 22:09:26 +00:00
|
|
|
hoverImpl: hoverImpl{text: r.Text},
|
2020-03-24 20:21:55 +00:00
|
|
|
rect: sprite.Rect,
|
|
|
|
}
|
|
|
|
|
|
|
|
d.hoverables = append(d.hoverables, ni)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-03-26 22:09:26 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2020-03-24 20:21:55 +00:00
|
|
|
// 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),
|
2020-03-26 22:09:26 +00:00
|
|
|
hoverImpl: hoverImpl{text: r.Text},
|
2020-03-24 20:21:55 +00:00
|
|
|
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
|
2020-03-23 00:33:29 +00:00
|
|
|
}
|
|
|
|
|
2020-03-24 20:21:55 +00:00
|
|
|
func (n *noninteractive) regions(tick int) []region {
|
2020-03-26 22:09:26 +00:00
|
|
|
out := oneRegion(n.bounds().Min, n.frames.image(tick))
|
|
|
|
|
|
|
|
if n.textImg != nil {
|
|
|
|
out = append(out, oneRegion(n.bounds().Min, n.textImg)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return out
|
2020-03-23 00:33:29 +00:00
|
|
|
}
|