230 lines
5.1 KiB
Go
230 lines
5.1 KiB
Go
package ui
|
|
|
|
import (
|
|
"github.com/hajimehoshi/ebiten"
|
|
|
|
"code.ur.gs/lupine/ordoor/internal/menus"
|
|
)
|
|
|
|
// Setup handlers know how to handle each type of widget.
|
|
// TODO: it might be better to have a Widget interface and different structs for
|
|
// each type of widget, but let's see how far we can push this model.
|
|
var setupHandlers = map[menus.MenuType]func(i *Interface, r *menus.Record) error{
|
|
menus.TypeStatic: handleStatic,
|
|
menus.TypeMenu: nil,
|
|
menus.TypeButton: handleButton,
|
|
menus.TypeInvokeButton: handleInvokeButton,
|
|
menus.TypeOverlay: nil, // FIXME: What's it for?
|
|
menus.TypeHypertext: handleHypertext,
|
|
menus.TypeCheckbox: handleCheckbox,
|
|
menus.TypeAnimationSample: handleAnimation,
|
|
menus.TypeMainButton: handleMainButton,
|
|
menus.TypeSlider: nil, // FIXME: handle this
|
|
}
|
|
|
|
func handleStatic(i *Interface, record *menus.Record) error {
|
|
spriteId := record.Share
|
|
|
|
// FIXME: SpriteID takes precedence over SHARE if present, but is that right?
|
|
if len(record.SpriteId) > 0 && record.SpriteId[0] != -1 {
|
|
spriteId = record.SpriteId[0]
|
|
}
|
|
|
|
sprite, err := i.menu.Sprite(spriteId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
static := &noninteractive{
|
|
bounds: sprite.Rect,
|
|
frames: animation{sprite.Image},
|
|
tooltip: record.Desc,
|
|
}
|
|
|
|
i.static = append(i.static, static)
|
|
|
|
return nil
|
|
}
|
|
|
|
// A hypertext is static, but we should only take the bounds from "SHARE", not
|
|
// display anything.
|
|
func handleHypertext(i *Interface, record *menus.Record) error {
|
|
sprite, err := i.menu.Sprite(record.Share)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
static := &noninteractive{
|
|
bounds: sprite.Rect,
|
|
frames: nil,
|
|
tooltip: record.Desc,
|
|
}
|
|
|
|
i.static = append(i.static, static)
|
|
|
|
return nil
|
|
}
|
|
|
|
// A checkbox has 3 sprites, and 3 states: unchecked, checked, disabled.
|
|
func handleCheckbox(i *Interface, record *menus.Record) error {
|
|
widget, err := i.widgetFromRecord(record, record.Share)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
unchecked := widget.sprite
|
|
disabled, err := i.menu.Sprite(record.Share + 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
checked, err := i.menu.Sprite(record.Share + 2)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
widget.Value = "0"
|
|
|
|
widget.OnMouseClick = func() {
|
|
if widget.Value == "1" { // Click disables
|
|
widget.Value = "0"
|
|
} else { // Click enables
|
|
widget.Value = "1"
|
|
}
|
|
}
|
|
|
|
widget.disabledImage = disabled.Image
|
|
widget.valueToImage = func() *ebiten.Image {
|
|
if widget.Value == "1" {
|
|
return checked.Image
|
|
}
|
|
|
|
return unchecked.Image
|
|
}
|
|
|
|
i.widgets = append(i.widgets, widget)
|
|
|
|
return nil
|
|
}
|
|
|
|
// An animation is a non-interactive element that displays something in a loop
|
|
func handleAnimation(i *Interface, record *menus.Record) error {
|
|
sprite, err := i.menu.Sprite(record.SpriteId[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
frames, err := i.menu.Images(record.SpriteId[0], record.DrawType)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ani := &noninteractive{
|
|
bounds: sprite.Rect,
|
|
frames: animation(frames),
|
|
tooltip: record.Desc,
|
|
}
|
|
|
|
i.static = append(i.static, ani)
|
|
|
|
return nil
|
|
}
|
|
|
|
func handleButton(i *Interface, record *menus.Record) error {
|
|
spriteId := record.SpriteId[0]
|
|
widget, err := i.widgetFromRecord(record, spriteId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pressed, err := i.menu.Sprite(spriteId + 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
disabled, err := i.menu.Sprite(spriteId + 2)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
widget.mouseButtonDownImage = pressed.Image
|
|
widget.disabledImage = disabled.Image
|
|
|
|
i.widgets = append(i.widgets, widget)
|
|
|
|
return nil
|
|
}
|
|
|
|
func handleInvokeButton(i *Interface, record *menus.Record) error {
|
|
widget, err := i.widgetFromRecord(record, record.Share)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pressed, err := i.menu.Sprite(record.Share + 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
disabled, err := i.menu.Sprite(record.Share + 2)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
widget.mouseButtonDownImage = pressed.Image
|
|
widget.disabledImage = disabled.Image
|
|
|
|
i.widgets = append(i.widgets, widget)
|
|
|
|
return nil
|
|
}
|
|
|
|
// A main button is quite complex. It has 3 main sprites and a hover animation
|
|
func handleMainButton(i *Interface, record *menus.Record) error {
|
|
widget, err := i.widgetFromRecord(record, record.Share)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
pressed, err := i.menu.Sprite(record.Share + 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
disabled, err := i.menu.Sprite(record.Share + 2)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hovers, err := i.menu.Images(record.SpriteId[0], record.DrawType)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
widget.mouseButtonDownImage = pressed.Image
|
|
widget.disabledImage = disabled.Image
|
|
widget.hoverAnimation = animation(hovers)
|
|
|
|
i.widgets = append(i.widgets, widget)
|
|
|
|
return nil
|
|
}
|
|
|
|
// Widgets need a bounding box determined by a sprite. Different widgets specify
|
|
// their sprites in different attributes, so pass in the right sprite externally
|
|
func (i *Interface) widgetFromRecord(record *menus.Record, spriteId int) (*Widget, error) {
|
|
sprite, err := i.menu.Sprite(spriteId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
widget := &Widget{
|
|
Bounds: sprite.Rect,
|
|
Tooltip: record.Desc,
|
|
path: record.Path(),
|
|
record: record,
|
|
sprite: sprite,
|
|
}
|
|
|
|
return widget, nil
|
|
}
|