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: nil, // FIXME: handle this 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 := &staticElement{ bounds: sprite.Rect, image: 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 := &staticElement{ bounds: sprite.Rect, image: 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 } 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 = 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 } var path []int for r := record; r != nil; r = r.Parent { path = append([]int{r.Id}, path...) } widget := &Widget{ Bounds: sprite.Rect, Tooltip: record.Desc, path: path, record: record, sprite: sprite, } return widget, nil }